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

# API REST

Ingest expose l’API sur le port 8080 du Service `fineparser-ingest`. Soumettez des documents, interrogez périodiquement les tâches jusqu’à ce qu’elles soient terminées, puis téléchargez les résultats.

L’API ne comporte aucune authentification. Avant de l’exposer, placez-la derrière un composant chargé d’authentifier les appelants. Voir [Exposer l’API](https://docs.abbyy.com/fr/fine-parser/enterprise/best-practices/production-deployment.md#exposing-the-api).

| Point de terminaison | Rôle |
| - | - |
| `POST /parse` | Soumettre un ou plusieurs documents. |
| `GET /jobs/{jobId}` | Statut d’une tâche. |
| `GET /batch/{batchId}` | Statut de toutes les tâches issues d’une même requête. |
| `GET /jobs/{jobId}/{name}` | Télécharger un résultat. |

```bash cURL theme={null}
# Soumettre
curl -s -F files=@invoice.pdf -F outputTypes=json http://localhost:8080/parse
# {"jobs":[{"file":"invoice.pdf","jobId":"e08f769f-..."}]}

# Interroger périodiquement
curl -s http://localhost:8080/jobs/e08f769f-...
# {"status":"successful","files":["e08f769f-.../invoice.json"],...}

# Télécharger
curl -OJ http://localhost:8080/jobs/e08f769f-.../invoice.json
```

```python Python theme={null}
import pathlib, time

import requests

FP = "http://localhost:8080"

with open("invoice.pdf", "rb") as f:
    r = requests.post(f"{FP}/parse", files={"files": f}, data={"outputTypes": ["json"]})
r.raise_for_status()
job = r.json()["jobs"][0]["jobId"]

while (status := requests.get(f"{FP}/jobs/{job}").json())["status"] in ("pending", "in-progress"):
    time.sleep(3)
if status["status"] != "successful":
    raise RuntimeError(status["failure"])

for entry in status["files"]:
    r = requests.get(f"{FP}/jobs/{entry}")
    r.raise_for_status()
    pathlib.Path(pathlib.Path(entry).name).write_bytes(r.content)
```

## POST /parse

Une requête `multipart/form-data`.

| Champ | Obligatoire | Valeur |
| - | - | - |
| `files` | Oui | Un PDF ou une image, par exemple au format PNG, JPEG ou TIFF. Répétez le champ pour en envoyer plusieurs. |
| `outputTypes` | Oui | `doclang`, `json`, `xml` ou `txt`. Répétez le champ pour en indiquer plusieurs. Voir [Formats de sortie](https://docs.abbyy.com/fr/fine-parser/enterprise/basics/output-formats.md). |
| `baseProfile` | Non | Un profil de reconnaissance prédéfini. Nécessite `userIni`. |
| `userIni` | Non | Un profil utilisateur, sous forme de champ ou de fichier. Nécessite `baseProfile`. Voir [Paramètres de reconnaissance](https://docs.abbyy.com/fr/fine-parser/enterprise/basics/recognition-settings.md#per-request-profiles). |

La réponse renvoyée est `202 Accepted`, avec un ID de tâche par fichier. Une requête comportant plusieurs fichiers renvoie également un `batchId`. Les fichiers qui n’ont pas pu être acceptés sont répertoriés sous `errors`.

```json theme={null}
{"batchId":"c5a6dd90-...","jobs":[{"file":"a.pdf","jobId":"c2f11bb8-..."},{"file":"b.pdf","jobId":"2ab42551-..."}]}
```

`POST /parse` n’est pas idempotent. Une nouvelle soumission après l’expiration du délai d’attente peut créer des tâches en double.

## GET /jobs/{jobId}

| Champ | Signification |
| - | - |
| `status` | `pending`, `in-progress`, `successful` ou `failed`. |
| `files` | Si `successful` : une entrée par résultat, sous la forme `{jobId}/{name}`. |
| `durationSeconds` | Si `successful` : durée en secondes entre la soumission et la fin du traitement. |
| `failure` | Si `failed` : `{"reason": ..., "message": ...}`. |

Le statut d’une tâche terminée est conservé pendant `orchestrator.jobRetentionSeconds` (24 heures par défaut). Passé ce délai, ce point de terminaison renvoie `404`, mais les résultats restent téléchargeables.

| `reason` | Action à effectuer |
| - | - |
| `profile-rejected` | Corrigez le paramètre du profil mentionné dans le message. |
| `ingest-failed` | Vérifiez que le fichier s’ouvre correctement. Il est peut-être corrompu ou dans un format non pris en charge. |
| `never-started` | Soumettez-le de nouveau. |
| `recognition-failed` | Soumettez-le une nouvelle fois. En cas de nouvel échec, le document est probablement illisible. |
| `finalize-failed` | Vérifiez le volume de sortie, puis soumettez-le de nouveau. |
| `timed-out` | Voir [Taille des unités et baux](https://docs.abbyy.com/fr/fine-parser/enterprise/concepts/scaling.md#unit-size-and-leases). |

## GET /batch/{batchId}

Renvoie le `status` de l’ensemble de la requête, ainsi que `jobs`, qui contient pour chaque tâche les champs `jobId`, `file` et `status`, sous la même forme que `GET /jobs/{jobId}`. Un lot n’a le statut `successful` que si toutes ses tâches l’ont également.

## GET /jobs/{jobId}/{name}

Télécharge un résultat. Chaque entrée de `files` est déjà de la forme `{jobId}/{name}` ; il suffit donc de l'ajouter à la suite de `/jobs/`. Le téléchargement ne supprime rien.

## Erreurs

Les erreurs sont renvoyées au format JSON : `{"error":{"code":"...","message":"..."}}`. Basez votre traitement sur la valeur de `code`.

| `code` | HTTP | Signification |
| - | - | - |
| `invalid_request` | 400 | Un champ est manquant ou non valide. Le message précise lequel. |
| `no_files_accepted` | 400 | Aucun fichier n'a pu être accepté. `errors` en indique la raison pour chacun. |
| `not_found` | 404 | Tâche, lot, fichier ou chemin introuvable. |
| `method_not_allowed` | 405 | Méthode HTTP incorrecte. |
| `upload_too_large` | 413 | La taille de la requête dépasse `ingest.maxUploadSize`. |
| `orchestrator_error` | 502 | Erreur interne inattendue. |
| `orchestrator_unavailable` | 503 | Service momentanément indisponible. Réessayez après le délai en secondes indiqué par `Retry-After`. |

## Limites

| Limite | Paramètre |
| - | - |
| Taille de la requête, tous fichiers confondus | `ingest.maxUploadSize` |
| Parties de formulaire multipart par requête, fichiers et `outputTypes` confondus | 5 000 |
| Taille de `userIni` | 1 Mio |

## CORS

Pour appeler l'API depuis un navigateur situé sur une autre origine, indiquez les origines autorisées dans `ingest.cors.allowedOrigins`, en les séparant par des virgules. Par défaut, aucune origine n'est autorisée.
