# Upload de áudio e vídeo

> Envie até 95 MB de uma vez. Para arquivos de até 2 GB, use o upload em partes e continue de onde parou se a conexão cair.

Canonical: https://transcript1.com/pt/docs/uploads
Language: pt-BR
Last updated: 2026-10-14

Para transcrever um arquivo, envie o áudio ou vídeo por upload. O transcript1 usa speech-to-text com IA, então `source` aceita apenas `auto` ou `stt`. As opções de idioma e identificação de falantes, `language` e `diarize`, estão em [Links aceitos e opções](https://transcript1.com/pt/docs/sources-and-options).

## Formatos e tamanhos aceitos

Confira a extensão antes de enviar: aceitamos `mp3`, `wav`, `m4a`, `flac`, `ogg`, `opus`, `mp4`, `mov`, `webm` e `mkv`. Se o nome terminar com outra extensão, a API responde `422 unsupported_media`. O arquivo também precisa ter uma faixa de áudio. Sem ela, a transcrição falha com `unsupported_media`.

| Limite | Valor |
|---|---|
| Arquivo enviado de uma vez (`multipart/form-data`) | 95 MB |
| Arquivo enviado em partes | 2 GB (2.000.000.000 bytes). O limite do seu plano pode ser menor. |
| Uploads em partes ainda abertos por equipe | 20 |

Se o arquivo ultrapassar o limite, a resposta será `413 media_too_large`. O campo `max_bytes` informa o tamanho máximo permitido.

## Envie o arquivo de uma vez

Até 95 MB, basta chamar `POST /v1/transcriptions` com `multipart/form-data`. Use o campo `file` para o arquivo. Se precisar, adicione `language`, `diarize` (`true` ou `false`), `source` (`auto` ou `stt`) e `webhook_url` como campos do formulário.

```bash
curl -X POST "https://api.transcript1.com/v1/transcriptions?wait=60" \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY" \
  -F file=@interview.m4a \
  -F language=en \
  -F diarize=true
```

A API devolve o objeto da transcrição com `source.platform` definido como `upload`. Assim como nos links de vídeo, o status HTTP é `202` enquanto o processamento continua e `200` quando termina. Se você enviar um arquivo vazio, receberá `422 invalid_request`.

## Envie arquivos grandes em partes

O upload em partes permite continuar o envio se a conexão cair. Primeiro crie o upload, envie as partes e confirme a conclusão. Se houver uma interrupção, consulte o que já chegou antes de continuar.

### 1. Crie o upload

Informe o nome e o tamanho do arquivo no corpo JSON. Você também pode passar `mime_type`. Use o cabeçalho `Idempotency-Key`: com ele, você pode repetir essa chamada sem criar outra transcrição.

```bash
curl -X POST "https://api.transcript1.com/v1/transcriptions" \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY" \
  -H "Idempotency-Key: interview-2026-10-13" \
  -H "Content-Type: application/json" \
  -d '{"upload":{"filename":"interview.m4a","size":48210334,"mime_type":"audio/mp4"},"language":"auto","diarize":true}'
```

Você recebe HTTP `201`, status `awaiting_upload` e as instruções de envio em `upload`:

```json
{
  "id": "tr_8fK2Lm0PqRsTuVwXyZaBcD",
  "object": "transcription",
  "status": "awaiting_upload",
  "upload": {
    "chunk_url_template": "https://api.transcript1.com/v1/transcriptions/tr_8fK2Lm0PqRsTuVwXyZaBcD/upload/chunks/{index}",
    "headers": { "X-Upload-Token": "t1u_..." },
    "expires_at": "2026-10-13T10:30:00.000Z",
    "chunks": [
      { "index": 0, "offset": 0, "size": 8388608 },
      { "index": 1, "offset": 8388608, "size": 8388608 }
    ]
  }
}
```

O servidor divide o arquivo em partes de aproximadamente 8 MiB (8.388.608 bytes) e lista os tamanhos e posições em `chunks`. O exemplo acima mostra só parte da lista. Guarde o `X-Upload-Token` como segredo: ele dá acesso a esse upload por 1 hora, até `expires_at`.

### 2. Envie cada parte

Para cada item de `chunks`, substitua `{index}` em `chunk_url_template` pelo `index` e faça um `PUT`. Leia o arquivo a partir de `offset` e envie exatamente `size` bytes no corpo, com o tipo `application/octet-stream`. Nessa chamada, a autenticação usa `X-Upload-Token`; você não precisa de `Authorization`.

```bash
curl -X PUT "https://api.transcript1.com/v1/transcriptions/tr_8fK2Lm0PqRsTuVwXyZaBcD/upload/chunks/0" \
  -H "X-Upload-Token: t1u_..." \
  -H "Content-Type: application/octet-stream" \
  --data-binary @chunk-0.bin
```

A confirmação de cada parte tem o formato `{ "object": "upload_chunk", "index": 0, "size": 8388608 }`. Se você repetir o envio, a nova parte substitui a anterior. Tamanho diferente do previsto ou índice fora da lista gera `422 invalid_request`. Sem token, ou com token expirado, a API responde `401 unauthorized`.

### 3. Continue após uma interrupção

Consulte `GET /v1/transcriptions/:id/upload` para saber quais partes o servidor já recebeu:

```json
{
  "object": "upload",
  "status": "awaiting_upload",
  "total_bytes": 48210334,
  "uploaded_bytes": 16777216,
  "received_chunks": [0, 1],
  "chunks": [ { "index": 0, "offset": 0, "size": 8388608 } ],
  "expires_at": "2026-10-13T10:30:00.000Z"
}
```

Compare a lista completa com `received_chunks` e envie só as partes que ainda faltam. Se o token tiver expirado, faça de novo a chamada do passo 1, sem mudar `Idempotency-Key` nem os parâmetros. Você recebe a mesma transcrição e um token novo para continuar.

### 4. Conclua o upload

```bash
curl -X POST "https://api.transcript1.com/v1/transcriptions/tr_8fK2Lm0PqRsTuVwXyZaBcD/upload/complete" \
  -H "Authorization: Bearer $TRANSCRIPT1_API_KEY"
```

Ao chamar `POST /v1/transcriptions/:id/upload/complete`, o servidor confere o tamanho de todas as partes, monta o arquivo e coloca a transcrição na fila. A resposta é `202` com o objeto da transcrição.

Se alguma parte não chegou, a API responde `409 upload_incomplete` e lista os índices em `missing_chunks`. Envie essas partes e tente concluir novamente. Se o upload já terminou ou foi cancelado, a resposta é `409 invalid_state`. Depois de concluir o envio, acompanhe a transcrição com `GET /v1/transcriptions/:id?wait=60` ou receba um [webhook](https://transcript1.com/pt/docs/webhooks).

### Exemplo completo em Python

```python
import os
import requests

API = "https://api.transcript1.com"
auth = {"Authorization": f"Bearer {os.environ['TRANSCRIPT1_API_KEY']}"}
path = "interview.m4a"

created = requests.post(
    f"{API}/v1/transcriptions",
    headers={**auth, "Idempotency-Key": "interview-2026-10-13"},
    json={"upload": {"filename": os.path.basename(path), "size": os.path.getsize(path)}},
)
created.raise_for_status()
transcription = created.json()
upload = transcription["upload"]

with open(path, "rb") as file:
    for chunk in upload["chunks"]:
        file.seek(chunk["offset"])
        url = upload["chunk_url_template"].replace("{index}", str(chunk["index"]))
        response = requests.put(
            url,
            data=file.read(chunk["size"]),
            headers={**upload["headers"], "Content-Type": "application/octet-stream"},
        )
        response.raise_for_status()

done = requests.post(f"{API}/v1/transcriptions/{transcription['id']}/upload/complete", headers=auth)
done.raise_for_status()
print(done.json()["status"])
```

## Limites e exclusão dos arquivos

- Cada equipe pode manter até 20 uploads em `awaiting_upload` ao mesmo tempo. Se tentar abrir mais um, receberá `429 too_many_active_jobs` com `Retry-After`.
- Você tem 24 horas a partir da criação para concluir o upload. Depois desse prazo, cancelamos o envio e excluímos as partes.
- Excluímos o áudio ou vídeo 24 horas depois de a transcrição chegar a `completed`, `failed` ou `canceled`. O texto fica salvo até você chamar `DELETE /v1/transcriptions/:id`.
- Assim que sabemos a duração do arquivo, cobramos os minutos, sempre arredondando para cima. Se a transcrição falhar ou você cancelar, não há cobrança. Veja [Planos, minutos e limites](https://transcript1.com/pt/docs/billing-and-limits).
