# Référence API Documents — Upload, Statut & bbox

> Téléchargez des documents et images, interrogez leur statut d'extraction, récupérez une image de page ou un recadrage normalisé, et déclenchez la localisation facultative des boîtes englobantes pour l'API v1 d'ImageToTable.ai.

Un **Document** est une page unique traitée — une image téléchargée, ou une page extraite d'un PDF téléchargé. Chaque Document appartient à un [Batch](/developers/reference/batches) (identifié par `batch_name`), qui est l'unité sur laquelle vous lancez réellement le traitement. Le téléchargement d'un PDF multipage crée *un Document par page* dans le même batch — voir [Télécharger un document](#upload-a-document) ci-dessous.

## Télécharger un document

Télécharge un fichier unique (image ou PDF) dans un batch. Si `batch_name` est omis, un nom est généré automatiquement et renvoyé dans la réponse. Le téléchargement ne démarre pas l'extraction — appelez [Démarrer le traitement d'un batch](/developers/reference/batches#start-processing-a-batch) une fois que vous avez téléchargé tout ce que vous souhaitez traiter ensemble. Le champ `remaining_batch_capacity` de la réponse vous indique combien de documents supplémentaires ce batch peut accepter avant d'atteindre la taille maximale de votre plan (voir `max_batch_size` du [Compte](/developers/reference/account)) — utile pour décider côté client s'il faut continuer à ajouter des documents à ce batch ou en créer un nouveau, sans requête séparée.

`POST /api/v1/documents`

### Paramètres

| Nom | Emplacement | Type | Description |
| --- | --- | --- | --- |
| file | body (multipart) | fichier | Obligatoire si url n'est pas fourni. Une image (JPEG/PNG/etc.) ou un PDF. Les PDF sont limités à 30 pages par téléversement et sont découpés en un Document par page. |
| url | body (multipart) | chaîne, optionnel | Alternative à file — le serveur télécharge le fichier depuis cette URL au lieu de devoir l'attacher. Mutuellement exclusif avec file ; ne passer qu'un seul des deux. Doit être une URL publique http:// ou https:// (pas d'adresse locale/réseau privé) ; le téléchargement est limité à 30 Mo avec un délai d'attente de 15 secondes. |
| batch_name | body (multipart) | chaîne, optionnel | Batch auquel ajouter ce Document. Omettre pour générer automatiquement un nouveau nom de batch (renvoyé dans la réponse). Réutiliser la même valeur pour plusieurs téléversements afin de constituer un batch avant de le traiter. |
| template_id | body (multipart) | entier, optionnel | Un ID de Template appartenant à votre compte, à pré-associer à ce Document. Non obligatoire — vous pouvez aussi passer un template (ou des champs ad hoc) lors de l'appel à process . |
| password | body (multipart) | chaîne, optionnel | PDF uniquement. Tenté en premier si le fichier est protégé par mot de passe. S'il est omis ou ne déverrouille pas le fichier, on utilise les mots de passe déjà enregistrés dans les paramètres Email Inbox de votre compte — ce champ ne nécessite pas d'avoir configuré Email Inbox, c'est simplement une alternative par appel. |
| Idempotency-Key | en-tête, optionnel | chaîne | Réessai sans risque. Voir Idempotence . |

**Les téléversements PDF renvoient un tableau, pas un ID unique.** Téléverser un PDF transforme chaque page en son propre Document et le champ `document_id` de la réponse devient un tableau JSON (une chaîne par page, dans l'ordre des pages), plus un champ `page_count`. Un téléversement d'image unique renvoie une chaîne scalaire. Un code client qui suppose que `document_id` est toujours une chaîne échouera avec un PDF — vérifiez si le fichier envoyé est un PDF et adaptez-vous à la forme de la réponse, ou envoyez toujours des images sans jamais compter sur le cas scalaire. Voir les deux exemples de réponse à droite.

### Erreurs possibles

- `missing_api_key` / `invalid_api_key` / `plan_required` — voir [Gestion des erreurs](/developers/guides/errors).
- `missing_parameter` — ni `file` ni `url` n'ont été envoyés.
- `invalid_parameter` (`param: "file"`) — image ou PDF invalide/corrompu, PDF protégé par mot de passe qui n'a pas pu être déverrouillé (ni le champ `password` ni aucun mot de passe Email Inbox enregistré n'a fonctionné), ou PDF dépassant la limite de 30 pages.
- `invalid_parameter` (`param: "url"`) — `file` et `url` ont été envoyés ensemble, l'URL ne pointe pas vers une adresse publique, le téléchargement a échoué ou expiré, ou le fichier téléchargé dépasse 30 Mo.
- `invalid_parameter` (`param: "batch_name"`) — le batch a déjà atteint la taille maximale autorisée par votre formule.
- `invalid_parameter` (`param: "template_id"`) ou `template_not_found`.
- `rate_limit_exceeded` — trop de documents non traités (en file d'attente) sur le compte ; traitez-en ou supprimez-en d'abord.

## Récupérer un document

Récupère le statut actuel d'un seul document et, une fois l'extraction réussie, ses `line_items` remodelés. C'est l'équivalent pour un seul document de [Récupérer les résultats d'un batch](/developers/reference/batches#get-batch-results) — mêmes règles de remodelage, mais sans l'option `?include=bbox` (disponible uniquement sur le point de terminaison des résultats au niveau du batch).

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

### Paramètres

| Nom | Emplacement | Type | Description |
| --- | --- | --- | --- |
| document_id | chemin | chaîne | L'identifiant du document renvoyé par POST /documents (ou une entrée de ce tableau, pour une page PDF). |

`status` est toujours l'une des valeurs suivantes : `queued`, `processing`, `succeeded`, `failed`, `canceled` — voir le guide [Modèle asynchrone](/developers/guides/async-model) pour la machine à états. `completed_at` est défini une fois que le document atteint un état terminal (`succeeded`, `failed` ou `canceled`) et reste `null` avant cela.

### Erreurs possibles

- `missing_api_key` / `invalid_api_key` / `plan_required` — voir [Gestion des erreurs](/developers/guides/errors).
- `document_not_found` — aucun document avec cet identifiant sur votre compte.

## Obtenir l'image d'un document

Renvoie l'image de la page d'un document — la page entière par défaut, ou un recadrage normalisé avec `?crop=`. C'est ce qui alimente `image_url` sur les champs de localisation pure (voir [Obtenir les résultats d'un batch](/developers/reference/batches#get-batch-results)), mais vous pouvez aussi l'appeler directement avec vos propres coordonnées.

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

### Paramètres

| Nom | Emplacement | Type | Description |
| --- | --- | --- | --- |
| document_id | chemin | chaîne | L'identifiant du document. |
| crop | requête, optionnel | chaîne | "x1,y1,x2,y2" — quatre nombres flottants entre 0 et 1, suivant la même convention de coordonnées normalisées que tout objet bbox ailleurs dans l'API. Omettez pour obtenir l'image de la page entière, non recadrée. |

La réponse est constituée des octets bruts de l'image (`Content-Type: image/jpeg`), pas du JSON — il n'y a pas d'exemple de réponse JSON à droite pour ce point de terminaison, seulement la requête.

### Erreurs possibles

- `missing_api_key` / `invalid_api_key` / `plan_required` — voir [Gestion des erreurs](/developers/guides/errors).
- `document_not_found` — aucun document avec cet identifiant, ou le fichier image d'origine n'est plus disponible (par exemple, il dépasse la fenêtre de conservation avec suppression automatique de votre compte).
- `invalid_parameter` (`param: "crop"`) — valeur `crop` mal formée, coordonnées en dehors de 0–1, ou région de recadrage vide après ajustement aux limites de l'image.

## Déclencher l'annotation bbox

Lance explicitement la tâche optionnelle **payante** de second passage qui localise l'emplacement physique de chaque valeur de champ extraite sur la page. Il s'agit d'une action facturable distincte de l'extraction elle-même — consultez le guide [Bounding Boxes](/developers/guides/bbox) avant d'intégrer cette fonctionnalité, en particulier la note concernant le paramètre `auto_annotate_bbox` de votre compte qui pourrait déclencher (et facturer) automatiquement cette même tâche sans que vous n'ayez jamais à appeler ce point d'accès.

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

### Paramètres

| Nom | Emplacement | Type | Description |
| --- | --- | --- | --- |
| document_id | chemin | string | Doit déjà être un document succeeded avec des données extraites — vous ne pouvez pas annoter un document dont l'extraction n'est pas terminée. |
| Idempotency-Key | en-tête, optionnel | string | Recommandé — cette action consomme des crédits. Voir Idempotence . |

Renvoie **202** lorsqu'une nouvelle tâche bbox vient d'être mise en file d'attente, ou **200** lorsqu'une tâche *bbox* pour ce document était déjà en cours d'exécution (`already_running: true`) — ce qui signifie que vous avez déjà appelé ce même point d'accès pour ce document auparavant et que cette tâche bbox antérieure n'est pas encore terminée. Ceci est indépendant du fait que l'extraction du document soit terminée ou non — bbox ne peut être déclenché que sur un document déjà `succeeded` (voir « Erreurs possibles » ci-dessous), donc au moment où vous pouvez appeler ce point d'accès, l'extraction est déjà terminée. `already_running` concerne uniquement une *seconde tâche bbox* pour le même document, et non la tâche d'extraction. Dans les deux cas (202 ou 200), rien de nouveau n'est démarré ou facturé sur le chemin 200 — interrogez [Obtenir l'annotation bbox](#get-bbox-annotation) avec le `group_batch_id` renvoyé pour obtenir le résultat.

### Erreurs possibles

- `missing_api_key` / `invalid_api_key` / `plan_required` — voir [Gestion des erreurs](/developers/guides/errors).
- `document_not_found` — aucun Document avec cet identifiant sur votre compte.
- `insufficient_credits` — crédits insuffisants pour exécuter cette passe d'annotation.
- `invalid_parameter` — le Document n'est pas dans un état valide pour cette opération (toujours en cours de traitement), ou ne contient pas de données extraites pour localiser les boîtes.

## Obtenir l'annotation bbox

Interroge le statut et récupère les résultats du dernier job d'annotation bbox déclenché pour un Document. Si aucun job n'a jamais été déclenché pour ce Document, `exists` est `false` et `status`/`group_batch_id` sont `null` — il s'agit d'une réponse normale et courante (la plupart des Documents n'ont jamais de bbox déclenché), et non d'une erreur.

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

### Paramètres

| Nom | Emplacement | Type | Description |
| --- | --- | --- | --- |
| document_id | path | string | L'identifiant du Document. |

`rows` associe un index de ligne (sous forme de chaîne, ex. `"0"`) à une correspondance de nom de champ → objet `bbox` normalisé (ou `null` si l'emplacement de ce champ n'a pas été trouvé sur la page). `status` utilise la même énumération fermée à 5 valeurs qu'ailleurs dans l'API.

### Erreurs possibles

- `missing_api_key` / `invalid_api_key` / `plan_required` — voir [Gestion des erreurs](/developers/guides/errors).
- `document_not_found` — aucun Document avec cet identifiant sur votre compte.

## Code Examples

### Télécharger un document

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

### Télécharger un document — depuis une URL

POST /api/v1/documents

Aucun fichier local requis — cet exemple est exécutable tel quel, car `invoice.webp` est un fichier réel hébergé sur notre propre 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());
```

### Réponse — image unique

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

### Réponse — PDF multipage

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

### Obtenir un document

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

### Réponse

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

### Obtenir l'image d'un document — page entière

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

### Obtenir l'image d'un document — recadrée

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

### Déclencher l'annotation 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());
```

### Réponse — 202, nouveau job

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

### Réponse — 200, déjà en cours

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

Rien de nouveau n'a été démarré ni facturé — un appel antérieur à ce même endpoint pour ce Document a déjà un job en cours. Interrogez [Get bbox annotation](#get-bbox-annotation) avec le même `group_batch_id` dans les deux cas.

### Obtenir l'annotation 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());
```

### Réponse

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