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

# Tokens de Upload Blob

> Gere um token de upload de curta duração com POST /v1/upload-tokens para que um navegador faça upload direto para o Blob Storage sem a sua chave de API.

<ParamField header="Authorization" type="string" placeholder="Chave da API" required>
  A chave da API para sua conta. Você pode encontrá-la nas [configurações da conta](https://squarecloud.app/pt-br/account/security).
</ParamField>

O Tokens de Upload permite que o seu **servidor** gere um token de curta duração que um **navegador** ou app mobile usa para fazer upload diretamente para o Blob Storage. O arquivo nunca passa pelo seu servidor, e a sua chave de API nunca sai dele. Exige o escopo `blob:write` e um plano pago.

O token vai no cabeçalho `Authorization` do [Envio de Objeto](/pt-br/blob-reference/endpoint/post) ou das rotas de [upload em partes](/pt-br/blob-reference/endpoint/chunked-init), e não funciona em nenhum outro lugar (`403 UPLOAD_TOKEN_NOT_ALLOWED`). Tudo o que você define ao gerá-lo fica **fixado**: o navegador não pode mudar o nome, o prefixo, a visibilidade, a expiração nem os metadados, enviar um arquivo maior ou usar outro tipo de arquivo.

* Cada upload gasta um uso: uma chamada ao Envio de Objeto, ou a abertura de um upload em partes (as partes e a conclusão dele não gastam mais).
* Sem um `name`, o navegador escolhe o nome e ele sempre recebe um security hash, então um token vazado nunca pode substituir os seus arquivos existentes.
* O token deixa de funcionar quando os usos se esgotam (`401 UPLOAD_TOKEN_USED`), quando expira ou quando a chave de API que o gerou é revogada (`401 ACCESS_DENIED`).

<ParamField body="name" type="string">
  Fixa o nome do arquivo. Sem ele, o navegador envia `name` na query.
</ParamField>

<ParamField body="prefix" type="string">
  Fixa o prefixo. Um navegador que envia um prefixo diferente recebe `403 PREFIX_NOT_ALLOWED`.
</ParamField>

<ParamField body="private" type="boolean">
  Fixa a visibilidade.
</ParamField>

<ParamField body="security_hash" type="boolean">
  Apenas com `name`: `false` permite que o upload substitua o arquivo com esse nome. Caso contrário, o nome sempre recebe um hash.
</ParamField>

<ParamField body="expire" type="string | null">
  Fixa a expiração (`30d`, `6h`), ou `null` para nenhuma. Abaixo de 7 dias exige Enterprise.
</ParamField>

<ParamField body="max_size" type="number">
  Tamanho máximo do arquivo em bytes, de 512 a 10737418240 (10 GiB).
</ParamField>

<ParamField body="allowed_extensions" type="string[]">
  Extensões aceitas, de 1 a 20, em minúsculas e sem o ponto (`png`, `tar.gz`).
</ParamField>

<ParamField body="metadata" type="object">
  Metadados adicionados a todo arquivo enviado com o token. Somente Pro e Enterprise.
</ParamField>

<ParamField body="expires_in" type="number" default="900">
  Por quanto tempo o token dura, de 60 a 3600 segundos.
</ParamField>

<ParamField body="max_uses" type="number" default="1">
  Quantos uploads o token permite, de 1 a 100.
</ParamField>

### Limites de taxa

<Note>120 tokens por minuto (`RATE_LIMITED`, 429). Gerar um token não armazena nada, então um token por upload de usuário final não é problema.</Note>

### Resposta

<ResponseField name="status" type="string">
  "success" se bem-sucedida, "error" caso contrário.
</ResponseField>

<ResponseField name="response" type="object">
  <Expandable title="Alternar objeto">
    <ResponseField name="token" type="string">
      O token de upload (`squp_...`). Entregue-o ao navegador.
    </ResponseField>

    <ResponseField name="expires_at" type="ISO 8601">
      Quando o token expira.
    </ResponseField>

    <ResponseField name="max_uses" type="number">
      Quantos uploads o token permite.
    </ResponseField>
  </Expandable>
</ResponseField>

<RequestExample>
  ```javascript Servidor (Node.js) theme={null}
  // Your backend: mint a token for the signed-in user and return it to the page.
  const res = await fetch('https://blob.squarecloud.app/v1/upload-tokens', {
    method: 'POST',
    headers: {
      Authorization: process.env.SQUARE_API_KEY,
      'Content-Type': 'application/json',
    },
    body: JSON.stringify({
      prefix: `avatars/${userId}`,
      allowed_extensions: ['png', 'jpg', 'webp'],
      max_size: 2 * 1024 * 1024,
      expires_in: 300,
    }),
  });
  const { response } = await res.json();
  // send response.token to the browser
  ```

  ```javascript Navegador theme={null}
  const form = new FormData();
  form.append('file', input.files[0]);

  const res = await fetch('https://blob.squarecloud.app/v1/objects?name=avatar', {
    method: 'POST',
    headers: { Authorization: token },
    body: form,
  });
  const { response } = await res.json();
  // response.url is the public URL of the new file
  ```

  ```bash cURL theme={null}
  curl --request POST \
    --url 'https://blob.squarecloud.app/v1/upload-tokens' \
    --header 'Authorization: YOUR_API_KEY' \
    --header 'Content-Type: application/json' \
    --data '{ "prefix": "avatars", "allowed_extensions": ["png", "jpg"], "max_size": 2097152 }'
  ```
</RequestExample>

<ResponseExample>
  ```json theme={null}
  {
    "status": "success",
    "response": {
      "token": "squp_Tq7xLm2Vb9Rk4Wz1Nc8Hy5Js0Gd3Fp6Ae.Hq3mZ8vT1kLw9xRb",
      "expires_at": "2026-09-25T12:15:00.000Z",
      "max_uses": 1
    }
  }
  ```
</ResponseExample>

### Erros

| Código                                                                                                                                                            | HTTP | Quando                                                                     |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---- | -------------------------------------------------------------------------- |
| `INVALID_BODY`                                                                                                                                                    | 400  | O corpo não é um objeto JSON.                                              |
| `INVALID_OBJECT_NAME` / `INVALID_OBJECT_PREFIX` / `INVALID_OBJECT_PRIVATE` / `INVALID_OBJECT_SECURITY_HASH` / `INVALID_OBJECT_EXPIRE` / `INVALID_OBJECT_METADATA` | 400  | Um valor fixado é inválido.                                                |
| `INVALID_MAX_SIZE` / `INVALID_ALLOWED_EXTENSIONS` / `INVALID_EXPIRES_IN` / `INVALID_MAX_USES`                                                                     | 400  | Um limite está fora do intervalo.                                          |
| `UPLOAD_TOKEN_TOO_LARGE`                                                                                                                                          | 400  | Opções demais para um token. Encurte os metadados ou a lista de extensões. |
| `PERMISSION_DENIED`                                                                                                                                               | 401  | A conta não tem um plano pago ativo.                                       |
| `UPGRADE_REQUIRED`                                                                                                                                                | 403  | A expiração ou os metadados exigem um plano superior.                      |
| `RATE_LIMITED`                                                                                                                                                    | 429  | Mais de 120 tokens em um minuto.                                           |

Quando o navegador faz o upload: `401 UPLOAD_TOKEN_USED` (usos esgotados), `401 ACCESS_DENIED` (expirado ou revogado), `403 PREFIX_NOT_ALLOWED` (outro prefixo), `400 FILE_TYPE_NOT_ALLOWED` (extensão não permitida) e `413 FILE_TOO_LARGE` (acima de `max_size`).
