# Referência da API de Documentos — Upload, Status e bbox

> Faça upload de documentos e imagens, consulte o status de extração, obtenha uma imagem de página ou um recorte normalizado dela e acione a localização opcional de bounding boxes para a API v1 do ImageToTable.ai.

Um **Documento** é uma página processada individualmente — uma imagem enviada, ou uma página renderizada de um PDF enviado. Cada Documento pertence a um [Lote](/developers/reference/batches) (identificado por `batch_name`), que é a unidade que você realmente inicia o processamento. Enviar um PDF com várias páginas cria *um Documento por página* no mesmo lote — veja [Fazer upload de um documento](#upload-a-document) abaixo.

## Fazer upload de um documento

Envia um único arquivo (imagem ou PDF) para um lote. Se `batch_name` for omitido, um será gerado automaticamente e retornado na resposta. O upload não inicia a extração — chame [Iniciar processamento de um lote](/developers/reference/batches#start-processing-a-batch) assim que você tiver enviado tudo o que deseja processar em conjunto. O campo `remaining_batch_capacity` da resposta informa quantos documentos adicionais este lote pode aceitar antes de atingir o tamanho máximo do seu plano (veja `max_batch_size` em [Conta](/developers/reference/account)) — útil para decidir no lado do cliente se deve continuar adicionando a este lote ou iniciar um novo, sem uma consulta separada.

`POST /api/v1/documents`

### Parâmetros

| Nome | Localização | Tipo | Descrição |
| --- | --- | --- | --- |
| file | body (multipart) | file | Obrigatório, a menos que url seja fornecido. Uma imagem (JPEG/PNG/etc.) ou um PDF. PDFs são limitados a 30 páginas por upload e são divididos em um Documento por página. |
| url | body (multipart) | string, opcional | Alternativa a file — o servidor baixa o arquivo desta URL em vez de você precisar anexá-lo. Mutuamente exclusivo com file ; forneça exatamente um. Deve ser uma URL pública http:// ou https:// (sem endereços localhost/rede privada); o download é limitado a 30MB com um tempo limite de leitura de 15 segundos. |
| batch_name | body (multipart) | string, opcional | Lote ao qual adicionar este documento. Omita para gerar automaticamente um novo nome de lote (retornado na resposta). Reutilize o mesmo valor em vários uploads para construir um lote antes de processá-lo. |
| template_id | body (multipart) | integer, opcional | Um ID de Modelo pertencente à sua conta para pré-associar a este documento. Não é obrigatório — você também pode passar um modelo (ou campos ad-hoc) ao chamar process . |
| password | body (multipart) | string, opcional | Apenas PDF. Tentado primeiro se o arquivo estiver protegido por senha. Se omitido, ou se não desbloquear o arquivo, recorre a quaisquer senhas já salvas nas configurações de Email Inbox da sua conta — este campo não exige que você tenha o Email Inbox configurado, é apenas uma alternativa por chamada a ele. |
| Idempotency-Key | header, opcional | string | Seguro para repetir. Consulte Idempotência . |

**Uploads de PDF retornam um array, não um único ID.** Fazer upload de um PDF renderiza cada página como seu próprio Documento e o `document_id` da resposta se torna um array JSON (uma string por página, na ordem das páginas), além de um campo `page_count`. Um upload de imagem única retorna uma string escalar. Código cliente que assume que `document_id` é sempre uma string falhará em um upload de PDF — verifique se o arquivo que você está enviando é um PDF e ramifique com base na forma da resposta, ou sempre envie imagens e nunca dependa do caso escalar. Consulte os dois exemplos de resposta à direita.

### Possíveis erros

- `missing_api_key` / `invalid_api_key` / `plan_required` — consulte [Tratamento de Erros](/developers/guides/errors).
- `missing_parameter` — nem `file` nem `url` foram enviados.
- `invalid_parameter` (`param: "file"`) — imagem ou PDF inválido/corrompido, PDF protegido por senha que não pôde ser desbloqueado (nem o campo `password` nem nenhuma senha salva do Email Inbox funcionaram), ou PDF com mais de 30 páginas.
- `invalid_parameter` (`param: "url"`) — tanto `file` quanto `url` foram enviados, a URL não resolve para um endereço público, o download falhou ou expirou, ou o arquivo baixado excede 30MB.
- `invalid_parameter` (`param: "batch_name"`) — o lote já atingiu o tamanho máximo do seu plano.
- `invalid_parameter` (`param: "template_id"`) ou `template_not_found`.
- `rate_limit_exceeded` — muitos documentos não processados (na fila) já existem na conta; processe ou exclua alguns primeiro.

## Obter um documento

Recupera o status atual de um único documento e, após a extração bem-sucedida, seus `line_items` remodelados. Este é o equivalente para um único documento de [Obter resultados do lote](/developers/reference/batches#get-batch-results) — mesmas regras de remodelagem, mas sem a opção `?include=bbox` (disponível apenas no endpoint de resultados em nível de lote).

`GET /api/v1/documents/{document_id}`

### Parâmetros

| Nome | Localização | Tipo | Descrição |
| --- | --- | --- | --- |
| document_id | path | string | O ID do documento retornado por POST /documents (ou uma entrada desse array, para uma página de PDF). |

`status` é sempre um dos valores `queued`, `processing`, `succeeded`, `failed`, `canceled` — consulte o guia [Modelo Assíncrono](/developers/guides/async-model) para a máquina de estados. `completed_at` é definido quando o documento atinge um estado terminal (`succeeded`, `failed` ou `canceled`) e permanece `null` antes disso.

### Erros possíveis

- `missing_api_key` / `invalid_api_key` / `plan_required` — consulte [Tratamento de Erros](/developers/guides/errors).
- `document_not_found` — nenhum Documento com este ID em sua conta.

## Obter a imagem de um Documento

Retorna a imagem da página de um Documento — a página completa por padrão, ou um recorte normalizado dela com `?crop=`. É isso que alimenta `image_url` em campos de localização pura (consulte [Obter resultados do lote](/developers/reference/batches#get-batch-results)), mas você também pode chamá-lo diretamente com suas próprias coordenadas.

`GET /api/v1/documents/{document_id}/image`

### Parâmetros

| Nome | Localização | Tipo | Descrição |
| --- | --- | --- | --- |
| document_id | path | string | O ID do Documento. |
| crop | query, opcional | string | "x1,y1,x2,y2" — quatro floats entre 0 e 1, mesma convenção de coordenadas normalizadas de todo objeto bbox em outras partes da API. Omita para obter a imagem de página completa e sem recorte. |

A resposta são os bytes brutos da imagem (`Content-Type: image/jpeg`), não JSON — não há exemplo de resposta JSON à direita para este endpoint, apenas a requisição.

### Erros possíveis

- `missing_api_key` / `invalid_api_key` / `plan_required` — consulte [Tratamento de Erros](/developers/guides/errors).
- `document_not_found` — nenhum Documento com este ID, ou o arquivo de imagem original não está mais disponível (ex.: ultrapassou a janela de retenção de exclusão automática da sua conta).
- `invalid_parameter` (`param: "crop"`) — valor `crop` malformado, coordenadas fora de 0–1, ou uma região de recorte vazia após o ajuste aos limites da imagem.

## Acionar anotação de bbox

Inicia explicitamente o job opcional e **pago** de segunda passagem que localiza onde cada valor de campo extraído está fisicamente na página. Esta é uma ação faturada separada da extração em si — consulte o guia [Bounding Boxes](/developers/guides/bbox) antes de integrar isso, especialmente a nota sobre a configuração `auto_annotate_bbox` da sua conta que pode acionar (e cobrar) este mesmo job automaticamente sem que você nunca chame este endpoint.

`POST /api/v1/documents/{document_id}/bbox`

### Parâmetros

| Nome | Localização | Tipo | Descrição |
| --- | --- | --- | --- |
| document_id | path | string | Deve ser um documento já succeeded com dados extraídos — você não pode anotar um documento que ainda não concluiu a extração. |
| Idempotency-Key | header, opcional | string | Recomendado — esta ação gasta créditos. Consulte Idempotência . |

Retorna **202** quando um novo job de bbox acaba de ser enfileirado, ou **200** quando um job de *bbox* para este documento já está em execução (`already_running: true`) — significando que você já chamou este mesmo endpoint para este documento uma vez antes e aquele job de bbox anterior ainda não terminou. Isso não tem relação com a conclusão da extração do próprio documento — bbox só pode ser acionado em um documento que já está `succeeded` (veja "Erros possíveis" abaixo), então quando você pode chamar este endpoint, a extração já está concluída. `already_running` é puramente sobre um *segundo job de bbox* para o mesmo documento, não sobre o job de extração. De qualquer forma (202 ou 200), nada novo é iniciado ou cobrado no caminho 200 — consulte [Obter anotação de bbox](#get-bbox-annotation) com o `group_batch_id` retornado para obter o resultado.

### Possíveis erros

- `missing_api_key` / `invalid_api_key` / `plan_required` — consulte [Tratamento de Erros](/developers/guides/errors).
- `document_not_found` — nenhum documento com este ID em sua conta.
- `insufficient_credits` — créditos insuficientes para executar esta passagem de anotação.
- `invalid_parameter` — o documento não está em um estado válido para isso (ainda processando) ou não possui dados extraídos para localizar caixas.

## Obter anotação bbox

Consulta o status e obtém os resultados do trabalho de anotação bbox mais recente acionado para um documento. Se nenhum trabalho foi acionado para este documento, `exists` é `false` e `status`/`group_batch_id` são `null` — esta é uma resposta normal e comum (a maioria dos documentos nunca tem bbox acionado), não um erro.

`GET /api/v1/documents/{document_id}/bbox`

### Parâmetros

| Nome | Localização | Tipo | Descrição |
| --- | --- | --- | --- |
| document_id | path | string | O ID do documento. |

`rows` mapeia um índice de linha (como string, ex. `"0"`) para um mapa de nome de campo → objeto `bbox` normalizado (ou `null` se a localização daquele campo não foi encontrada na página). `status` usa o mesmo conjunto fechado de 5 valores de enumeração usado em toda a API.

### Possíveis erros

- `missing_api_key` / `invalid_api_key` / `plan_required` — consulte [Tratamento de Erros](/developers/guides/errors).
- `document_not_found` — nenhum documento com este ID em sua conta.

## Code Examples

### Fazer upload de um documento

POST /api/v1/documents

**cURL**

```bash
curl -X POST https://imagetotable.ai/api/v1/documents \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "file=@invoice.jpg" \
  -F "batch_name=july-invoices"
```

**Python**

```python
import os
import uuid
import requests

response = requests.post(
    "https://imagetotable.ai/api/v1/documents",
    headers={
        "Authorization": f"Bearer {os.environ['API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    files={"file": open("invoice.jpg", "rb")},
    data={"batch_name": "july-invoices"},
)
print(response.json())
```

**Javascript**

```javascript
import { readFile } from "node:fs/promises";

const formData = new FormData();
formData.append("file", new Blob([await readFile("invoice.jpg")]), "invoice.jpg");
formData.append("batch_name", "july-invoices");

const response = await fetch("https://imagetotable.ai/api/v1/documents", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.API_KEY}`,
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: formData,
});
console.log(await response.json());
```

### Fazer upload de um documento — a partir de uma URL

POST /api/v1/documents

Nenhum arquivo local é necessário — este exemplo exato pode ser executado como está, já que `invoice.webp` é um arquivo real hospedado em nosso próprio site.

**cURL**

```bash
curl -X POST https://imagetotable.ai/api/v1/documents \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: $(uuidgen)" \
  -F "url=https://imagetotable.ai/static/samples/invoice.webp" \
  -F "batch_name=july-invoices"
```

**Python**

```python
import os
import uuid
import requests

response = requests.post(
    "https://imagetotable.ai/api/v1/documents",
    headers={
        "Authorization": f"Bearer {os.environ['API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
    data={
        "url": "https://imagetotable.ai/static/samples/invoice.webp",
        "batch_name": "july-invoices",
    },
)
print(response.json())
```

**Javascript**

```javascript
const formData = new FormData();
formData.append("url", "https://imagetotable.ai/static/samples/invoice.webp");
formData.append("batch_name", "july-invoices");

const response = await fetch("https://imagetotable.ai/api/v1/documents", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.API_KEY}`,
    "Idempotency-Key": crypto.randomUUID(),
  },
  body: formData,
});
console.log(await response.json());
```

### Resposta — imagem única

```json
{
  "document_id": "8f14e45f-ceea-467e-9de1-a3e9c93a9c95",
  "batch_name": "july-invoices",
  "remaining_batch_capacity": 199
}
```

### Resposta — PDF com várias páginas

```json
{
  "document_id": [
    "8f14e45f-ceea-467e-9de1-a3e9c93a9c95_p1",
    "8f14e45f-ceea-467e-9de1-a3e9c93a9c95_p2"
  ],
  "batch_name": "july-invoices",
  "page_count": 2,
  "remaining_batch_capacity": 198
}
```

### Obter um Documento

GET /api/v1/documents/{document_id}

**cURL**

```bash
curl https://imagetotable.ai/api/v1/documents/8f14e45f-ceea-467e-9de1-a3e9c93a9c95 \
  -H "Authorization: Bearer $API_KEY"
```

**Python**

```python
import os
import requests

response = requests.get(
    "https://imagetotable.ai/api/v1/documents/8f14e45f-ceea-467e-9de1-a3e9c93a9c95",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
)
print(response.json())
```

**Javascript**

```javascript
const response = await fetch("https://imagetotable.ai/api/v1/documents/8f14e45f-ceea-467e-9de1-a3e9c93a9c95", {
  headers: { "Authorization": `Bearer ${process.env.API_KEY}` },
});
console.log(await response.json());
```

### Resposta

```json
{
  "document_id": "8f14e45f-ceea-467e-9de1-a3e9c93a9c95",
  "batch_name": "july-invoices",
  "filename": "invoice_042.jpg",
  "status": "succeeded",
  "created_at": "2026-07-16T09:12:03+00:00",
  "started_at": "2026-07-16T09:12:05+00:00",
  "completed_at": "2026-07-16T09:12:14+00:00",
  "line_items": [
    {
      "invoice_number": "INV-1042",
      "invoice_date": "2026-07-01",
      "total_amount": "1,204.50"
    }
  ]
}
```

### Obter imagem de um documento — página inteira

GET /api/v1/documents/{document_id}/image

**cURL**

```bash
curl https://imagetotable.ai/api/v1/documents/8f14e45f-ceea-467e-9de1-a3e9c93a9c95/image \
  -H "Authorization: Bearer $API_KEY" \
  -o page.jpg
```

**Python**

```python
import os
import requests

response = requests.get(
    "https://imagetotable.ai/api/v1/documents/8f14e45f-ceea-467e-9de1-a3e9c93a9c95/image",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
)
with open("page.jpg", "wb") as f:
    f.write(response.content)
```

**Javascript**

```javascript
import { writeFile } from "node:fs/promises";

const response = await fetch("https://imagetotable.ai/api/v1/documents/8f14e45f-ceea-467e-9de1-a3e9c93a9c95/image", {
  headers: { "Authorization": `Bearer ${process.env.API_KEY}` },
});
await writeFile("page.jpg", Buffer.from(await response.arrayBuffer()));
```

### Obter imagem de um documento — recortada

GET /api/v1/documents/{document_id}/image?crop=...

**cURL**

```bash
curl "https://imagetotable.ai/api/v1/documents/8f14e45f-ceea-467e-9de1-a3e9c93a9c95/image?crop=0.10,0.08,0.42,0.30" \
  -H "Authorization: Bearer $API_KEY" \
  -o crop.jpg
```

**Python**

```python
import os
import requests

response = requests.get(
    "https://imagetotable.ai/api/v1/documents/8f14e45f-ceea-467e-9de1-a3e9c93a9c95/image",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
    params={"crop": "0.10,0.08,0.42,0.30"},
)
with open("crop.jpg", "wb") as f:
    f.write(response.content)
```

**Javascript**

```javascript
import { writeFile } from "node:fs/promises";

const url = new URL("https://imagetotable.ai/api/v1/documents/8f14e45f-ceea-467e-9de1-a3e9c93a9c95/image");
url.searchParams.set("crop", "0.10,0.08,0.42,0.30");

const response = await fetch(url, {
  headers: { "Authorization": `Bearer ${process.env.API_KEY}` },
});
await writeFile("crop.jpg", Buffer.from(await response.arrayBuffer()));
```

### Acionar anotação bbox

POST /api/v1/documents/{document_id}/bbox

**cURL**

```bash
curl -X POST https://imagetotable.ai/api/v1/documents/8f14e45f-ceea-467e-9de1-a3e9c93a9c95/bbox \
  -H "Authorization: Bearer $API_KEY" \
  -H "Idempotency-Key: $(uuidgen)"
```

**Python**

```python
import os
import uuid
import requests

response = requests.post(
    "https://imagetotable.ai/api/v1/documents/8f14e45f-ceea-467e-9de1-a3e9c93a9c95/bbox",
    headers={
        "Authorization": f"Bearer {os.environ['API_KEY']}",
        "Idempotency-Key": str(uuid.uuid4()),
    },
)
print(response.json())
```

**Javascript**

```javascript
const response = await fetch("https://imagetotable.ai/api/v1/documents/8f14e45f-ceea-467e-9de1-a3e9c93a9c95/bbox", {
  method: "POST",
  headers: {
    "Authorization": `Bearer ${process.env.API_KEY}`,
    "Idempotency-Key": crypto.randomUUID(),
  },
});
console.log(await response.json());
```

### Resposta — 202, novo job

```json
{
  "document_id": "8f14e45f-ceea-467e-9de1-a3e9c93a9c95",
  "group_batch_id": "bx_8a3c2e1f",
  "status": "queued",
  "already_running": false,
  "row_groups": 1
}
```

### Resposta — 200, já em execução

```json
{
  "document_id": "8f14e45f-ceea-467e-9de1-a3e9c93a9c95",
  "group_batch_id": "bx_8a3c2e1f",
  "status": "processing",
  "already_running": true,
  "row_groups": 1
}
```

Nada novo foi iniciado ou cobrado — uma chamada anterior a este mesmo endpoint para este Documento já possui um job em andamento. Consulte [Obter anotação bbox](#get-bbox-annotation) com o mesmo `group_batch_id` em ambos os casos.

### Obter anotação bbox

GET /api/v1/documents/{document_id}/bbox

**cURL**

```bash
curl https://imagetotable.ai/api/v1/documents/8f14e45f-ceea-467e-9de1-a3e9c93a9c95/bbox \
  -H "Authorization: Bearer $API_KEY"
```

**Python**

```python
import os
import requests

response = requests.get(
    "https://imagetotable.ai/api/v1/documents/8f14e45f-ceea-467e-9de1-a3e9c93a9c95/bbox",
    headers={"Authorization": f"Bearer {os.environ['API_KEY']}"},
)
print(response.json())
```

**Javascript**

```javascript
const response = await fetch("https://imagetotable.ai/api/v1/documents/8f14e45f-ceea-467e-9de1-a3e9c93a9c95/bbox", {
  headers: { "Authorization": `Bearer ${process.env.API_KEY}` },
});
console.log(await response.json());
```

### Resposta

```json
{
  "document_id": "8f14e45f-ceea-467e-9de1-a3e9c93a9c95",
  "exists": true,
  "status": "succeeded",
  "group_batch_id": "bx_8a3c2e1f",
  "rows": {
    "0": {
      "invoice_number": {"x1": 0.121, "y1": 0.084, "x2": 0.418, "y2": 0.112, "unit": "normalized"},
      "total_amount": null
    }
  }
}
```

---

Source: https://imagetotable.ai/pt/developers/reference/documents
