# Referencia de la API de Documentos — Carga, Estado y bbox

> Cargue documentos e imágenes, consulte su estado de extracción, obtenga una imagen de página o un recorte normalizado de la misma, y active la localización opcional de cuadros delimitadores para la API v1 de ImageToTable.ai.

Un **Documento** es una página procesada individual: una imagen cargada, o una página renderizada a partir de un PDF cargado. Cada Documento pertenece a un [Lote](/developers/reference/batches) (identificado por `batch_name`), que es la unidad que realmente se inicia para procesar. Cargar un PDF de varias páginas crea *un Documento por página* en el mismo lote; consulte [Cargar un documento](#upload-a-document) a continuación.

## Cargar un documento

Carga un único archivo (imagen o PDF) en un lote. Si se omite `batch_name`, se genera automáticamente uno y se devuelve en la respuesta. La carga no inicia la extracción; llame a [Iniciar procesamiento de un lote](/developers/reference/batches#start-processing-a-batch) una vez que haya cargado todo lo que desea procesar junto. El `remaining_batch_capacity` de la respuesta le indica cuántos documentos más puede aceptar este lote antes de alcanzar el tamaño máximo de lote de su plan (consulte [Cuenta](/developers/reference/account) `max_batch_size`), útil para decidir del lado del cliente si seguir añadiendo a este lote o iniciar uno nuevo, sin necesidad de una consulta adicional.

`POST /api/v1/documents`

### Parámetros

| Nombre | Ubicación | Tipo | Descripción |
| --- | --- | --- | --- |
| file | cuerpo (multipart) | archivo | Obligatorio a menos que se proporcione url . Una imagen (JPEG/PNG/etc.) o un PDF. Los PDF están limitados a 30 páginas por carga y se dividen en un Documento por página. |
| url | cuerpo (multipart) | cadena, opcional | Alternativa a file — el servidor descarga el archivo desde esta URL en lugar de que usted lo adjunte. Mutuamente excluyente con file ; pase exactamente uno. Debe ser una URL pública http:// o https:// (sin direcciones localhost/red privada); la descarga está limitada a 30 MB con un tiempo de espera de lectura de 15 segundos. |
| batch_name | cuerpo (multipart) | cadena, opcional | Lote al que agregar este documento. Omita para generar automáticamente un nuevo nombre de lote (devuelto en la respuesta). Reutilice el mismo valor en varias cargas para acumular un lote antes de procesarlo. |
| template_id | cuerpo (multipart) | entero, opcional | Un ID de Plantilla perteneciente a su cuenta para preasociar con este documento. No es obligatorio — también puede pasar una plantilla (o campos ad-hoc) cuando llame a process . |
| password | cuerpo (multipart) | cadena, opcional | Solo para PDF. Se prueba primero si el archivo está protegido por contraseña. Si se omite, o si no desbloquea el archivo, recurre a las contraseñas guardadas en la configuración de Email Inbox de su cuenta — este campo no requiere que tenga configurado Email Inbox, es solo una alternativa por llamada. |
| Idempotency-Key | encabezado, opcional | cadena | Seguro de reintentar. Consulte Idempotencia . |

**Las cargas de PDF devuelven un arreglo, no un solo ID.** Al cargar un PDF, cada página se convierte en su propio Documento y el `document_id` de la respuesta se convierte en un arreglo JSON (una cadena por página, en orden de página), más un campo `page_count`. Una carga de imagen única devuelve una cadena escalar. El código cliente que asume que `document_id` siempre es una cadena fallará con una carga de PDF — verifique si el archivo que envía es un PDF y bifurque según la forma de la respuesta, o envíe siempre imágenes y nunca dependa del caso escalar. Consulte los dos ejemplos de respuesta a la derecha.

### Posibles errores

- `missing_api_key` / `invalid_api_key` / `plan_required` — consulte [Manejo de errores](/developers/guides/errors).
- `missing_parameter` — no se envió ni `file` ni `url`.
- `invalid_parameter` (`param: "file"`) — imagen o PDF inválido o corrupto, PDF protegido con contraseña que no pudo desbloquearse (no funcionó ni el campo `password` ni ninguna contraseña guardada de Email Inbox), o PDF que supera el límite de 30 páginas.
- `invalid_parameter` (`param: "url"`) — se enviaron tanto `file` como `url`, la URL no resuelve a una dirección pública, la descarga falló o expiró, o el archivo descargado supera los 30 MB.
- `invalid_parameter` (`param: "batch_name"`) — el lote ya alcanzó el tamaño máximo de lote de su plan.
- `invalid_parameter` (`param: "template_id"`) o `template_not_found`.
- `rate_limit_exceeded` — ya hay demasiados documentos no procesados (en cola) en la cuenta; procese o elimine algunos primero.

## Obtener un documento

Obtiene el estado actual de un solo documento y, una vez que la extracción se haya completado con éxito, sus `line_items` reestructurados. Es el equivalente para un solo documento de [Obtener resultados del lote](/developers/reference/batches#get-batch-results) — mismas reglas de reestructuración, pero sin la opción `?include=bbox` (disponible solo en el endpoint de resultados a nivel de lote).

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

### Parámetros

| Nombre | Ubicación | Tipo | Descripción |
| --- | --- | --- | --- |
| document_id | ruta | string | El ID del documento devuelto por POST /documents (o una entrada de ese arreglo, para una página de PDF). |

`status` siempre es uno de `queued`, `processing`, `succeeded`, `failed`, `canceled` — consulte la guía del [Modelo asíncrono](/developers/guides/async-model) para conocer la máquina de estados. `completed_at` se establece cuando el documento alcanza un estado terminal (`succeeded`, `failed` o `canceled`) y permanece `null` antes de eso.

### Posibles errores

- `missing_api_key` / `invalid_api_key` / `plan_required` — consulte [Manejo de errores](/developers/guides/errors).
- `document_not_found` — no existe un documento con este ID en su cuenta.

## Obtener la imagen de un documento

Devuelve la imagen de la página detrás de un documento — la página completa por defecto, o un recorte normalizado de la misma con `?crop=`. Esto es lo que alimenta `image_url` en los campos de ubicación pura (consulte [Obtener resultados del lote](/developers/reference/batches#get-batch-results)), pero también puede llamarlo directamente con sus propias coordenadas.

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

### Parámetros

| Nombre | Ubicación | Tipo | Descripción |
| --- | --- | --- | --- |
| document_id | ruta | string | El ID del documento. |
| crop | consulta, opcional | string | "x1,y1,x2,y2" — cuatro flotantes entre 0 y 1, misma convención de coordenadas normalizadas que cualquier objeto bbox en la API. Omítalo para obtener la imagen de página completa sin recortar. |

La respuesta son los bytes de la imagen sin procesar (`Content-Type: image/jpeg`), no JSON — no hay ejemplo de respuesta JSON a la derecha para este endpoint, solo la solicitud.

### Posibles errores

- `missing_api_key` / `invalid_api_key` / `plan_required` — consulte [Manejo de errores](/developers/guides/errors).
- `document_not_found` — no existe un documento con este ID, o el archivo de imagen original ya no está disponible (p. ej., ha superado la ventana de retención de eliminación automática de su cuenta).
- `invalid_parameter` (`param: "crop"`) — valor de `crop` mal formado, coordenadas fuera del rango 0–1, o una región de recorte que queda vacía después de ajustarse a los límites de la imagen.

## Activar anotación de bbox

Inicia explícitamente el trabajo opcional (de **pago**) de segunda pasada que localiza dónde se encuentra físicamente en la página el valor de cada campo extraído. Esta es una acción facturable independiente de la extracción; consulte la guía [Bounding Boxes](/developers/guides/bbox) antes de integrarla, especialmente la nota sobre la configuración `auto_annotate_bbox` de su cuenta, que podría activar (y facturar) este mismo trabajo automáticamente sin que usted llame a este endpoint.

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

### Parámetros

| Nombre | Ubicación | Tipo | Descripción |
| --- | --- | --- | --- |
| document_id | ruta | string | Debe ser un documento succeeded con datos extraídos; no se puede anotar un documento cuya extracción aún no haya finalizado. |
| Idempotency-Key | encabezado, opcional | string | Recomendado: esta acción consume créditos. Consulte Idempotencia . |

Devuelve **202** cuando se acaba de encolar un nuevo trabajo de bbox, o **200** cuando ya se estaba ejecutando un trabajo de *bbox* para este documento (`already_running: true`), lo que significa que ya llamó a este mismo endpoint para este documento anteriormente y ese trabajo de bbox aún no ha finalizado. Esto no está relacionado con si la extracción del documento ya finalizó; bbox solo se puede activar en un documento que ya esté `succeeded` (consulte "Posibles errores" más abajo), por lo que cuando pueda llamar a este endpoint, la extracción ya estará completa. `already_running` se refiere exclusivamente a un *segundo trabajo de bbox* para el mismo documento, no al trabajo de extracción. En cualquier caso (202 o 200), no se inicia ni se cobra nada nuevo en la ruta 200; consulte [Obtener anotación de bbox](#get-bbox-annotation) con el `group_batch_id` devuelto para obtener el resultado.

### Posibles errores

- `missing_api_key` / `invalid_api_key` / `plan_required` — consulte [Manejo de errores](/developers/guides/errors).
- `document_not_found` — no hay ningún documento con este ID en su cuenta.
- `insufficient_credits` — no tiene suficientes créditos para ejecutar esta pasada de anotación.
- `invalid_parameter` — el documento aún no está en un estado válido para esto (todavía se está procesando) o no tiene datos extraídos para ubicar los cuadros.

## Obtener anotación bbox

Consulta el estado y obtiene los resultados del trabajo de anotación bbox más reciente activado para un documento. Si nunca se ha activado un trabajo para este documento, `exists` es `false` y `status`/`group_batch_id` son `null` — esta es una respuesta normal y común (la mayoría de los documentos nunca tienen bbox activado), no un error.

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

### Parámetros

| Nombre | Ubicación | Tipo | Descripción |
| --- | --- | --- | --- |
| document_id | ruta | string | El ID del documento. |

`rows` asigna un índice de fila (como cadena, p. ej. `"0"`) a un mapa de nombre de campo → objeto `bbox` normalizado (o `null` si no se encontró la ubicación de ese campo en la página). `status` utiliza la misma enumeración cerrada de 5 valores que en el resto de la API.

### Posibles errores

- `missing_api_key` / `invalid_api_key` / `plan_required` — consulte [Manejo de errores](/developers/guides/errors).
- `document_not_found` — no hay ningún documento con este ID en su cuenta.

## Code Examples

### Subir un 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());
```

### Subir un documento — desde una URL

POST /api/v1/documents

No se necesita un archivo local — este ejemplo exacto se puede ejecutar tal cual, ya que `invoice.webp` es un archivo real alojado en nuestro propio sitio.

**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());
```

### Respuesta — imagen única

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

### Respuesta — PDF de varias 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
}
```

### Obtener un 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());
```

### Respuesta

```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"
    }
  ]
}
```

### Obtener la imagen de un documento — página completa

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()));
```

### Obtener la imagen de un 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()));
```

### Activar anotación 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());
```

### Respuesta — 202, trabajo nuevo

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

### Respuesta — 200, ya en ejecución

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

No se inició ni cobró nada nuevo — una llamada anterior a este mismo endpoint para este documento ya tiene un trabajo en curso. Consulte [Obtener anotación bbox](#get-bbox-annotation) con el mismo `group_batch_id` en cualquier caso.

### Obtener anotación 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());
```

### Respuesta

```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/es/developers/reference/documents
