> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hustapp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Enviar mídia

> Fluxo de upload e envio de imagem, áudio, vídeo e documento

Enviar imagem, áudio, vídeo ou documento é um processo de três passos. O arquivo não sobe junto com a mensagem: você pede uma URL assinada, envia o arquivo direto para o storage e só então referencia o arquivo no envio.

<Steps>
  <Step title="Peça a URL assinada">
    `GET /file/signature` devolve a URL de upload e o identificador do arquivo.
  </Step>

  <Step title="Envie o arquivo">
    `PUT` na URL assinada, com o conteúdo binário. Esta requisição vai para o storage, não para a API do Hust, e não leva o seu token.
  </Step>

  <Step title="Envie a mensagem">
    `POST /message/send` com o `uuid` e o `filePath` recebidos no primeiro passo.
  </Step>
</Steps>

## 1. Obter a URL assinada

```http theme={null}
GET https://api.hustapp.com/file/signature
```

| Parâmetro     | Tipo      | Obrigatório         | Descrição                                                                                    |
| ------------- | --------- | ------------------- | -------------------------------------------------------------------------------------------- |
| `fileName`    | `string`  | Sim                 | Nome original do arquivo, com extensão. A extensão determina como o Hust classifica a mídia. |
| `contentType` | `string`  | Sim                 | Tipo MIME do arquivo. Por exemplo: `image/png`, `application/pdf`.                           |
| `tempFile`    | `boolean` | Não — padrão `true` | Quando `true`, o arquivo vai para um diretório temporário com **TTL de 48 horas**.           |

<CodeGroup>
  ```bash cURL theme={null}
  curl -G https://api.hustapp.com/file/signature \
    -H "Authorization: Bearer SEU_TOKEN" \
    --data-urlencode "fileName=comprovante.pdf" \
    --data-urlencode "contentType=application/pdf" \
    --data-urlencode "tempFile=true"
  ```

  ```javascript Node.js theme={null}
  const params = new URLSearchParams({
    fileName: "comprovante.pdf",
    contentType: "application/pdf",
    tempFile: "true",
  });

  const res = await fetch(`https://api.hustapp.com/file/signature?${params}`, {
    headers: { Authorization: `Bearer ${token}` },
  });

  const { signedUrl, uuid, filePath } = await res.json();
  ```

  ```python Python theme={null}
  import requests

  res = requests.get(
      "https://api.hustapp.com/file/signature",
      headers={"Authorization": f"Bearer {token}"},
      params={"fileName": "comprovante.pdf", "contentType": "application/pdf", "tempFile": "true"},
  )

  signature = res.json()
  ```

  ```php PHP theme={null}
  <?php
  $query = http_build_query([
      'fileName' => 'comprovante.pdf',
      'contentType' => 'application/pdf',
      'tempFile' => 'true',
  ]);

  $ch = curl_init("https://api.hustapp.com/file/signature?{$query}");
  curl_setopt_array($ch, [
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $token],
  ]);

  $response = curl_exec($ch);
  curl_close($ch);

  $signature = json_decode($response, true);
  ```

  ```pascal Delphi theme={null}
  uses
    System.Net.HttpClient, System.Net.URLClient, System.JSON;

  var
    HttpClient: THTTPClient;
    Response: IHTTPResponse;
    ResponseJson: TJSONObject;
    SignedUrl, FileUuid, FilePath: string;
  begin
    HttpClient := THTTPClient.Create;
    try
      HttpClient.CustomHeaders['Authorization'] := 'Bearer ' + Token;
      Response := HttpClient.Get(
        'https://api.hustapp.com/file/signature?fileName=comprovante.pdf' +
        '&contentType=application/pdf&tempFile=true');

      ResponseJson := TJSONObject.ParseJSONValue(Response.ContentAsString) as TJSONObject;
      try
        SignedUrl := ResponseJson.GetValue<string>('signedUrl');
        FileUuid := ResponseJson.GetValue<string>('uuid');
        FilePath := ResponseJson.GetValue<string>('filePath');
      finally
        ResponseJson.Free;
      end;
    finally
      HttpClient.Free;
    end;
  end;
  ```
</CodeGroup>

| Campo da resposta | Tipo     | Descrição                                                                    |
| ----------------- | -------- | ---------------------------------------------------------------------------- |
| `signedUrl`       | `string` | URL para onde você envia o arquivo. Tem validade curta.                      |
| `uuid`            | `string` | Identificador do arquivo no Hust. É o que você informa no envio da mensagem. |
| `filePath`        | `string` | Caminho do arquivo no storage.                                               |

<Warning>
  Com `tempFile: true`, o arquivo é apagado 48 horas depois do upload. Se a sua integração agenda envios ou guarda `uuid` para reutilizar depois, esse prazo precisa entrar na conta.
</Warning>

## 2. Enviar o arquivo

Faça um `PUT` na `signedUrl` com o conteúdo binário. Os dois cabeçalhos abaixo são obrigatórios, e o `Content-Type` precisa ser exatamente o mesmo que você informou no passo anterior.

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PUT "<signedUrl>" \
    -H "Content-Type: application/pdf" \
    -H "Content-Disposition: attachment; filename=comprovante.pdf" \
    --upload-file ./comprovante.pdf
  ```

  ```javascript Node.js theme={null}
  await fetch(signedUrl, {
    method: "PUT",
    headers: {
      "Content-Type": contentType,
      "Content-Disposition": `attachment; filename=${encodeURI(fileName)}`,
    },
    body: fileBuffer,
  });
  ```

  ```python Python theme={null}
  with open("comprovante.pdf", "rb") as f:
      requests.put(
          signed_url,
          data=f,
          headers={
              "Content-Type": "application/pdf",
              "Content-Disposition": "attachment; filename=comprovante.pdf",
          },
      )
  ```

  ```php PHP theme={null}
  <?php
  $ch = curl_init($signedUrl);
  curl_setopt_array($ch, [
      CURLOPT_CUSTOMREQUEST => 'PUT',
      CURLOPT_UPLOAD => true,
      CURLOPT_INFILE => fopen('comprovante.pdf', 'r'),
      CURLOPT_INFILESIZE => filesize('comprovante.pdf'),
      CURLOPT_HTTPHEADER => [
          'Content-Type: application/pdf',
          'Content-Disposition: attachment; filename=comprovante.pdf',
      ],
  ]);

  curl_exec($ch);
  curl_close($ch);
  ```

  ```pascal Delphi theme={null}
  uses
    System.Net.HttpClient, System.Classes;

  var
    HttpClient: THTTPClient;
    FileStream: TFileStream;
  begin
    HttpClient := THTTPClient.Create;
    try
      FileStream := TFileStream.Create('comprovante.pdf', fmOpenRead);
      try
        HttpClient.ContentType := 'application/pdf';
        HttpClient.CustomHeaders['Content-Disposition'] :=
          'attachment; filename=comprovante.pdf';
        HttpClient.Put(SignedUrl, FileStream);
      finally
        FileStream.Free;
      end;
    finally
      HttpClient.Free;
    end;
  end;
  ```
</CodeGroup>

O nome do arquivo no `Content-Disposition` deve ir codificado para URL, para suportar acentos e espaços.

<Note>
  Esta requisição **não** leva o cabeçalho `Authorization`. A autorização já está embutida na assinatura da URL.
</Note>

## 3. Enviar a mensagem

Use a mesma rota do envio de texto, trocando `type` pelo tipo da mídia e incluindo o objeto `file`. Os demais campos seguem as regras de [Enviar mensagem](/chat/enviar-mensagem): `connection` e `contact` obrigatórios, e `department` obrigatório salvo quando `called` é `"without"` ou traz um `id`.

| Campo            | Tipo      | Obrigatório                | Descrição                                                                                                      |
| ---------------- | --------- | -------------------------- | -------------------------------------------------------------------------------------------------------------- |
| `type`           | `string`  | Sim                        | `image`, `audio`, `video` ou `document`. O Hust não deduz o tipo a partir do arquivo neste fluxo.              |
| `file.uuid`      | `string`  | Sim                        | O `uuid` recebido no passo 1.                                                                                  |
| `file.filePath`  | `string`  | Ao usar arquivo temporário | O `filePath` recebido no passo 1.                                                                              |
| `file.forceFile` | `boolean` | Não — padrão `false`       | Força a entrega como anexo, em vez do WhatsApp renderizar a mídia embutida.                                    |
| `caption`        | `string`  | Não                        | Legenda da mídia. Sofre a mesma [assinatura automática](/chat/enviar-mensagem#assinatura-automatica) do texto. |

```json Exemplo theme={null}
{
  "type": "document",
  "caption": "Segue o comprovante do seu pedido.",
  "file": {
    "uuid": "1f8c2b7e-4a55-4f2b-9c31-0d7e5a9b2c44",
    "filePath": "temp/1f8c2b7e-4a55-4f2b-9c31-0d7e5a9b2c44.pdf"
  },
  "connection": { "uuid": "9db04f68-9e7d-4297-ba41-5f4d4c44779a" },
  "contact": { "phone": "5541988887777" },
  "department": { "id": 169070 }
}
```

<Warning>
  O envio não verifica se o upload do passo 2 foi concluído. Se você informar um `uuid` cujo arquivo nunca chegou ao storage, a rota responde `200` e a falha só aparece depois, no processamento da fila. Confirme que o `PUT` retornou sucesso antes de chamar o envio.
</Warning>

## Fluxo completo

Os três passos encadeados, do pedido da assinatura até a mensagem enviada:

<CodeGroup>
  ```javascript Node.js theme={null}
  // 1. Pede a URL assinada
  const params = new URLSearchParams({
    fileName: "comprovante.pdf",
    contentType: "application/pdf",
    tempFile: "true",
  });

  const signatureRes = await fetch(`https://api.hustapp.com/file/signature?${params}`, {
    headers: { Authorization: `Bearer ${token}` },
  });

  const { signedUrl, uuid, filePath } = await signatureRes.json();

  // 2. Envia o arquivo para o storage
  await fetch(signedUrl, {
    method: "PUT",
    headers: {
      "Content-Type": "application/pdf",
      "Content-Disposition": "attachment; filename=comprovante.pdf",
    },
    body: fileBuffer, // Buffer ou Blob do arquivo lido em disco
  });

  // 3. Envia a mensagem referenciando o arquivo
  const messageRes = await fetch("https://api.hustapp.com/message/send", {
    method: "POST",
    headers: {
      Authorization: `Bearer ${token}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      type: "document",
      caption: "Segue o comprovante do seu pedido.",
      file: { uuid, filePath },
      connection: { uuid: "9db04f68-9e7d-4297-ba41-5f4d4c44779a" },
      contact: { phone: "5541988887777" },
      called: "without",
    }),
  });

  const message = await messageRes.json();
  ```

  ```python Python theme={null}
  import requests

  # 1. Pede a URL assinada
  signature_res = requests.get(
      "https://api.hustapp.com/file/signature",
      headers={"Authorization": f"Bearer {token}"},
      params={
          "fileName": "comprovante.pdf",
          "contentType": "application/pdf",
          "tempFile": "true",
      },
  )
  signature = signature_res.json()
  signed_url, uuid, file_path = signature["signedUrl"], signature["uuid"], signature["filePath"]

  # 2. Envia o arquivo para o storage
  with open("comprovante.pdf", "rb") as f:
      requests.put(
          signed_url,
          data=f,
          headers={
              "Content-Type": "application/pdf",
              "Content-Disposition": "attachment; filename=comprovante.pdf",
          },
      )

  # 3. Envia a mensagem referenciando o arquivo
  message_res = requests.post(
      "https://api.hustapp.com/message/send",
      headers={"Authorization": f"Bearer {token}"},
      json={
          "type": "document",
          "caption": "Segue o comprovante do seu pedido.",
          "file": {"uuid": uuid, "filePath": file_path},
          "connection": {"uuid": "9db04f68-9e7d-4297-ba41-5f4d4c44779a"},
          "contact": {"phone": "5541988887777"},
          "called": "without",
      },
  )

  message = message_res.json()
  ```

  ```php PHP theme={null}
  <?php
  // 1. Pede a URL assinada
  $query = http_build_query([
      'fileName' => 'comprovante.pdf',
      'contentType' => 'application/pdf',
      'tempFile' => 'true',
  ]);

  $ch = curl_init("https://api.hustapp.com/file/signature?{$query}");
  curl_setopt_array($ch, [
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_HTTPHEADER => ['Authorization: Bearer ' . $token],
  ]);
  $signature = json_decode(curl_exec($ch), true);
  curl_close($ch);

  ['signedUrl' => $signedUrl, 'uuid' => $uuid, 'filePath' => $filePath] = $signature;

  // 2. Envia o arquivo para o storage
  $ch = curl_init($signedUrl);
  curl_setopt_array($ch, [
      CURLOPT_CUSTOMREQUEST => 'PUT',
      CURLOPT_UPLOAD => true,
      CURLOPT_INFILE => fopen('comprovante.pdf', 'r'),
      CURLOPT_INFILESIZE => filesize('comprovante.pdf'),
      CURLOPT_HTTPHEADER => [
          'Content-Type: application/pdf',
          'Content-Disposition: attachment; filename=comprovante.pdf',
      ],
  ]);
  curl_exec($ch);
  curl_close($ch);

  // 3. Envia a mensagem referenciando o arquivo
  $ch = curl_init('https://api.hustapp.com/message/send');
  curl_setopt_array($ch, [
      CURLOPT_POST => true,
      CURLOPT_RETURNTRANSFER => true,
      CURLOPT_HTTPHEADER => [
          'Authorization: Bearer ' . $token,
          'Content-Type: application/json',
      ],
      CURLOPT_POSTFIELDS => json_encode([
          'type' => 'document',
          'caption' => 'Segue o comprovante do seu pedido.',
          'file' => ['uuid' => $uuid, 'filePath' => $filePath],
          'connection' => ['uuid' => '9db04f68-9e7d-4297-ba41-5f4d4c44779a'],
          'contact' => ['phone' => '5541988887777'],
          'called' => 'without',
      ]),
  ]);

  $response = curl_exec($ch);
  curl_close($ch);

  $message = json_decode($response, true);
  ```

  ```pascal Delphi theme={null}
  uses
    System.Net.HttpClient, System.JSON, System.Classes;

  var
    HttpClient: THTTPClient;
    Response: IHTTPResponse;
    SignatureJson, RequestBody, Connection, Contact, FileObj: TJSONObject;
    SignedUrl, FileUuid, FilePath: string;
    FileStream: TFileStream;
  begin
    HttpClient := THTTPClient.Create;
    try
      // 1. Pede a URL assinada
      HttpClient.CustomHeaders['Authorization'] := 'Bearer ' + Token;
      Response := HttpClient.Get(
        'https://api.hustapp.com/file/signature?fileName=comprovante.pdf' +
        '&contentType=application/pdf&tempFile=true');

      SignatureJson := TJSONObject.ParseJSONValue(Response.ContentAsString) as TJSONObject;
      try
        SignedUrl := SignatureJson.GetValue<string>('signedUrl');
        FileUuid := SignatureJson.GetValue<string>('uuid');
        FilePath := SignatureJson.GetValue<string>('filePath');
      finally
        SignatureJson.Free;
      end;

      // 2. Envia o arquivo para o storage
      HttpClient.CustomHeaders['Authorization'] := '';
      FileStream := TFileStream.Create('comprovante.pdf', fmOpenRead);
      try
        HttpClient.ContentType := 'application/pdf';
        HttpClient.CustomHeaders['Content-Disposition'] :=
          'attachment; filename=comprovante.pdf';
        HttpClient.Put(SignedUrl, FileStream);
      finally
        FileStream.Free;
      end;

      // 3. Envia a mensagem referenciando o arquivo
      RequestBody := TJSONObject.Create;
      try
        Connection := TJSONObject.Create.AddPair('uuid', '9db04f68-9e7d-4297-ba41-5f4d4c44779a');
        Contact := TJSONObject.Create.AddPair('phone', '5541988887777');
        FileObj := TJSONObject.Create
          .AddPair('uuid', FileUuid)
          .AddPair('filePath', FilePath);

        RequestBody.AddPair('type', 'document');
        RequestBody.AddPair('caption', 'Segue o comprovante do seu pedido.');
        RequestBody.AddPair('file', FileObj);
        RequestBody.AddPair('connection', Connection);
        RequestBody.AddPair('contact', Contact);
        RequestBody.AddPair('called', 'without');

        HttpClient.CustomHeaders['Authorization'] := 'Bearer ' + Token;
        HttpClient.ContentType := 'application/json';
        Response := HttpClient.Post('https://api.hustapp.com/message/send',
          TStringStream.Create(RequestBody.ToJSON, TEncoding.UTF8));
      finally
        RequestBody.Free;
      end;
    finally
      HttpClient.Free;
    end;
  end;
  ```
</CodeGroup>

<Note>
  Neste exemplo o envio usa `called: "without"`, então não precisa de `department`. Se quiser abrir atendimento, troque por `department: { id: ... }` — veja [Modos de envio](/chat/enviar-mensagem#modos-de-envio).
</Note>
