Dernière mise à jour : 15 octobre 2026
Doc Extract API¶
Port local (Docker Compose) : 30002 | Repo : solyntek/djinn/services/djinn-doc-extract
Extraction de données structurées depuis factures, reçus, CV et pièces d'identité via OCR + LLM.
Endpoints¶
| Méthode | Route | Description |
|---|---|---|
GET |
/health |
Health check |
GET |
/v1/schemas |
Schémas des types de documents supportés |
POST |
/v1/extract |
Extraction depuis un fichier unique |
POST |
/v1/extract/batch |
Extraction batch depuis plusieurs fichiers |
POST |
/v1/extract/receipts/analyze |
Contrôle d'un lot de reçus (100 fichiers max) : doublons, écarts de politique, cohérence, authenticité |
GET / PUT |
/v1/receipt-policies |
Lire / remplacer la politique de dépenses de votre tenant |
Toutes les routes sauf /health exigent X-API-Key. Fichiers (multipart/form-data, champ file ou files) : .pdf, .docx, .png, .jpg, .jpeg, .tiff, .bmp, .gif, 50 Mio au plus chacun. document_type est optionnel : s'il est omis, le type est détecté depuis le texte.
Routage de la passerelle
La passerelle Kong route aujourd'hui /v1/extract/* et /v1/schemas. /v1/receipt-policies n'a pas encore de route publique sur la passerelle : elle est documentée ici car le service l'expose.
Types de documents¶
| Type | Données extraites |
|---|---|
invoice |
vendor, numéro, date, lignes, totaux, TVA, IBAN |
receipt |
vendor, date, lignes, totaux, mode de paiement |
resume |
nom, email, skills, expériences, diplômes, certifications |
id_card |
nom, date naissance, nationalité, numéro document |
rib |
titulaire, IBAN, BIC, banque, code guichet, numéro de compte, clé RIB |
Contrôle de reçus (/v1/extract/receipts/analyze)¶
Envoyez jusqu'à 100 reçus (files, categories optionnel : tableau JSON aligné par position sur les fichiers). Pour chaque reçu, la réponse donne les data extraites, les findings (écarts de cohérence interne comme total_mismatch ou future_date, et écarts de politique de dépenses comme amount_above_cap) et authenticity (l'avis de Doc Trust, ou null s'il n'a pas pu être obtenu : « non évalué », jamais « aucun signal »). duplicate_groups liste les reçus jugés être le même achat (rule : fingerprint ou vendor_date_amount). Ce sont des évaluations pour une relecture humaine, jamais des autorisations : aucun reçu n'est rejeté. Un fichier illisible ou en échec produit un item avec error et n'interrompt jamais le lot. La politique (currency, default_max_amount, caps par catégorie, require_vat_above) se définit avec PUT /v1/receipt-policies ; sans politique, une politique par défaut s'applique (is_default: true).
Erreurs¶
Les erreurs suivent le format FastAPI, {"detail": "..."} :
| Statut | Cause |
|---|---|
400 |
Extension de fichier non autorisée |
401 |
Clé API absente ou invalide |
413 |
Fichier de plus de 50 Mio ; plus de 100 reçus dans un lot de reçus |
422 |
PDF illisible (corrompu, pas un PDF, protégé par mot de passe), lot de reçus vide, categories ou politique invalide |
Sur /v1/extract/batch, un fichier trop volumineux ou en échec ne fait pas échouer l'appel : l'item revient avec confidence: 0 et un message error.
Exemple¶
{
"document_type": "resume",
"data": {
"firstname": "Jean",
"lastname": "Dupont",
"skills": ["Python", "Go", "Docker"],
"experiences": [{"company": "Acme", "title": "Senior Dev"}]
},
"confidence": 0.87
}
Référence interactive¶
Générée à chaque build depuis la spec versionnée openapi/doc-extract-v1.json (ADR-011) — aucune route documentée à la main.
Djinn Document Extract 0.2.0¶
Extraction de données structurées depuis factures, reçus, CVs, IDs et RIBs
Endpoints¶
GET /health¶
Health
Description
Health check endpoint.
Responses
GET /v1/schemas¶
Schemas
Description
List all supported document schemas with their fields.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
X-API-Key |
header | No |
Responses
POST /v1/extract¶
Extract
Description
Extract structured data from a single uploaded file.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
document_type |
query | No | |||
X-API-Key |
header | No |
Request body
Responses
{
"document_type": "invoice",
"data": null,
"text_source": null,
"raw_text": "string",
"confidence": 10.12,
"field_confidences": [
{
"field": "string",
"score": 10.12,
"reason": null
}
],
"pii_detected": null,
"error": null
}
Schema of the response body
{
"properties": {
"document_type": {
"$ref": "#/components/schemas/DocumentType"
},
"data": {
"anyOf": [
{
"$ref": "#/components/schemas/InvoiceData"
},
{
"$ref": "#/components/schemas/ReceiptData"
},
{
"$ref": "#/components/schemas/ResumeData"
},
{
"$ref": "#/components/schemas/IDCardData"
},
{
"$ref": "#/components/schemas/RibData"
},
{
"type": "null"
}
],
"title": "Data"
},
"text_source": {
"anyOf": [
{
"$ref": "#/components/schemas/TextSource"
},
{
"type": "null"
}
]
},
"raw_text": {
"type": "string",
"title": "Raw Text"
},
"confidence": {
"type": "number",
"maximum": 1.0,
"minimum": 0.0,
"title": "Confidence"
},
"field_confidences": {
"items": {
"$ref": "#/components/schemas/FieldConfidence"
},
"type": "array",
"title": "Field Confidences"
},
"pii_detected": {
"anyOf": [
{
"items": {
"additionalProperties": true,
"type": "object"
},
"type": "array"
},
{
"type": "null"
}
],
"title": "Pii Detected"
},
"error": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Error"
}
},
"type": "object",
"required": [
"document_type",
"raw_text",
"confidence"
],
"title": "ExtractionResult"
}
POST /v1/extract/batch¶
Extract Batch
Description
Extract structured data from multiple uploaded files.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
document_type |
query | No | |||
X-API-Key |
header | No |
Request body
Responses
[
{
"document_type": "invoice",
"data": null,
"text_source": null,
"raw_text": "string",
"confidence": 10.12,
"field_confidences": [
{
"field": "string",
"score": 10.12,
"reason": null
}
],
"pii_detected": null,
"error": null
}
]
GET /v1/receipt-policies¶
Get Receipt Policy V1
Description
Politique de dépenses du tenant authentifié, ou la politique par défaut.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
X-API-Key |
header | No |
Responses
{
"currency": "string",
"default_max_amount": 10.12,
"caps": [
{
"category": "string",
"max_amount": 10.12
}
],
"require_vat_above": null,
"is_default": true
}
Schema of the response body
{
"properties": {
"currency": {
"type": "string",
"maxLength": 3,
"minLength": 3,
"title": "Currency",
"default": "EUR"
},
"default_max_amount": {
"type": "number",
"minimum": 0.0,
"title": "Default Max Amount",
"default": 1000.0
},
"caps": {
"items": {
"$ref": "#/components/schemas/ExpenseCap"
},
"type": "array",
"title": "Caps"
},
"require_vat_above": {
"anyOf": [
{
"type": "number",
"minimum": 0.0
},
{
"type": "null"
}
],
"title": "Require Vat Above"
},
"is_default": {
"type": "boolean",
"title": "Is Default",
"default": false
}
},
"type": "object",
"title": "ExpensePolicyOut",
"description": "Politique renvoyée par l'API, avec l'indication qu'aucune n'a été enregistrée."
}
PUT /v1/receipt-policies¶
Put Receipt Policy V1
Description
Remplace la politique du tenant authentifié.
Le tenant vient de l'authentification (ADR-001) ; un tenant_id présent
dans le corps est ignoré, jamais honoré.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
X-API-Key |
header | No |
Request body
{
"currency": "string",
"default_max_amount": 10.12,
"caps": [
{
"category": "string",
"max_amount": 10.12
}
],
"require_vat_above": null
}
Schema of the request body
{
"properties": {
"currency": {
"type": "string",
"maxLength": 3,
"minLength": 3,
"title": "Currency",
"default": "EUR"
},
"default_max_amount": {
"type": "number",
"minimum": 0.0,
"title": "Default Max Amount",
"default": 1000.0
},
"caps": {
"items": {
"$ref": "#/components/schemas/ExpenseCap"
},
"type": "array",
"title": "Caps"
},
"require_vat_above": {
"anyOf": [
{
"type": "number",
"minimum": 0.0
},
{
"type": "null"
}
],
"title": "Require Vat Above"
}
},
"type": "object",
"title": "ExpensePolicy",
"description": "Politique de dépenses d'un tenant.\n\nLe verdict produit à partir de cette politique est une **évaluation**,\njamais une autorisation : doc-extract ne refuse aucun remboursement, il\nrapporte qu'un montant dépasse un plafond déclaré."
}
Responses
{
"currency": "string",
"default_max_amount": 10.12,
"caps": [
{
"category": "string",
"max_amount": 10.12
}
],
"require_vat_above": null,
"is_default": true
}
Schema of the response body
{
"properties": {
"currency": {
"type": "string",
"maxLength": 3,
"minLength": 3,
"title": "Currency",
"default": "EUR"
},
"default_max_amount": {
"type": "number",
"minimum": 0.0,
"title": "Default Max Amount",
"default": 1000.0
},
"caps": {
"items": {
"$ref": "#/components/schemas/ExpenseCap"
},
"type": "array",
"title": "Caps"
},
"require_vat_above": {
"anyOf": [
{
"type": "number",
"minimum": 0.0
},
{
"type": "null"
}
],
"title": "Require Vat Above"
},
"is_default": {
"type": "boolean",
"title": "Is Default",
"default": false
}
},
"type": "object",
"title": "ExpensePolicyOut",
"description": "Politique renvoyée par l'API, avec l'indication qu'aucune n'a été enregistrée."
}
POST /v1/extract/receipts/analyze¶
Analyze Receipts
Description
Analyse un lot de reçus : doublons, écarts de politique, cohérence, authenticité.
Pour chaque reçu : extraction (document_type="receipt"), empreinte
perceptuelle, contrôle de cohérence interne, confrontation à la
politique de dépenses du tenant, et avis d'authenticité de doc-trust
(la clé de l'appelant lui est transmise telle quelle, ADR-023 ; au plus
4 appels simultanés par lot). Puis, sur l'ensemble du lot,
rapprochement des doublons.
findings et authenticity sont des évaluations, jamais des
autorisations : cette route ne bloque rien, ne rejette aucun reçu pour
cause de constat, et ne modifie aucune politique. Un fichier illisible,
trop volumineux, ou dont l'extraction échoue, produit un item avec
error renseigné et n'interrompt jamais le lot — même contrat que
/v1/extract/batch. Seul un problème de requête (lot vide, lot
au-delà de MAX_BATCH_RECEIPTS) fait échouer l'appel entier.
authenticity vaut null quand l'avis n'a pas pu être obtenu (doc-trust
indisponible, format non pris en charge) : « non évalué », jamais « aucun
signal ». Cet échec n'interrompt pas le lot.
Input parameters
| Parameter | In | Type | Default | Nullable | Description |
|---|---|---|---|---|---|
X-API-Key |
header | string | No |
Request body
Schema of the request body
{
"properties": {
"files": {
"items": {
"type": "string",
"contentMediaType": "application/octet-stream"
},
"type": "array",
"title": "Files"
},
"categories": {
"anyOf": [
{
"type": "string"
},
{
"type": "null"
}
],
"title": "Categories"
}
},
"type": "object",
"required": [
"files"
],
"title": "Body_analyze_receipts_v1_extract_receipts_analyze_post"
}
Responses
{
"items": [
{
"index": 0,
"filename": "string",
"data": null,
"confidence": null,
"findings": [
{
"code": "string",
"message": "string",
"severity": "info"
}
],
"authenticity": null,
"error": null
}
],
"duplicate_groups": [
{
"indices": [
0
],
"rule": "fingerprint"
}
],
"analysed_at": "2022-04-13T15:42:05.901Z",
"policy_is_default": true
}
Schema of the response body
{
"properties": {
"items": {
"items": {
"$ref": "#/components/schemas/ReceiptAnalysisItem"
},
"type": "array",
"title": "Items"
},
"duplicate_groups": {
"items": {
"$ref": "#/components/schemas/DuplicateGroupOut"
},
"type": "array",
"title": "Duplicate Groups"
},
"analysed_at": {
"type": "string",
"format": "date-time",
"title": "Analysed At"
},
"policy_is_default": {
"type": "boolean",
"title": "Policy Is Default"
}
},
"type": "object",
"required": [
"items",
"analysed_at",
"policy_is_default"
],
"title": "ReceiptAnalysisResponse",
"description": "Réponse de l'analyse du lot.\n\nNe bloque rien, ne rejette aucun reçu pour cause de constat, et ne\nmodifie aucune politique de dépenses."
}
Schemas¶
AuthenticityOut¶
| Name | Type | Description |
|---|---|---|
explanation |
string | |
rules_version |
string | |
score |
number | |
signals |
Array<FindingOut> | |
verdict |
string |
Body_analyze_receipts_v1_extract_receipts_analyze_post¶
| Name | Type | Description |
|---|---|---|
categories |
||
files |
Array<string> |
Body_extract_batch_v1_extract_batch_post¶
| Name | Type | Description |
|---|---|---|
files |
Array<string> |
Body_extract_v1_extract_post¶
| Name | Type | Description |
|---|---|---|
file |
string |
Certification¶
| Name | Type | Description |
|---|---|---|
name |
||
provider |
||
year |
Diploma¶
| Name | Type | Description |
|---|---|---|
degree |
||
end_date |
||
field_of_study |
||
school |
||
start_date |
DocumentType¶
Type: string
DuplicateGroupOut¶
| Name | Type | Description |
|---|---|---|
indices |
Array<integer> | |
rule |
string |
ExpenseCap¶
| Name | Type | Description |
|---|---|---|
category |
string | |
max_amount |
number |
ExpensePolicy¶
| Name | Type | Description |
|---|---|---|
caps |
Array<ExpenseCap> | |
currency |
string | |
default_max_amount |
number | |
require_vat_above |
ExpensePolicyOut¶
| Name | Type | Description |
|---|---|---|
caps |
Array<ExpenseCap> | |
currency |
string | |
default_max_amount |
number | |
is_default |
boolean | |
require_vat_above |
Experience¶
| Name | Type | Description |
|---|---|---|
company |
||
description |
||
end_date |
YYYY-MM, YYYY, or 'Present' | |
location |
||
start_date |
YYYY-MM or YYYY | |
title |
ExtractionResult¶
| Name | Type | Description |
|---|---|---|
confidence |
number | |
data |
||
document_type |
DocumentType | |
error |
||
field_confidences |
Array<FieldConfidence> | |
pii_detected |
||
raw_text |
string | |
text_source |
FieldConfidence¶
| Name | Type | Description |
|---|---|---|
field |
string | |
reason |
||
score |
number |
FindingOut¶
| Name | Type | Description |
|---|---|---|
code |
string | |
message |
string | |
severity |
string |
HealthResponse¶
| Name | Type | Description |
|---|---|---|
status |
string | |
version |
string |
HTTPValidationError¶
| Name | Type | Description |
|---|---|---|
detail |
Array<ValidationError> |
IDCardData¶
| Name | Type | Description |
|---|---|---|
birth_date |
||
birth_place |
||
document_number |
||
expiry_date |
||
first_name |
||
gender |
M or F | |
issue_date |
||
last_name |
||
nationality |
InvoiceData¶
| Name | Type | Description |
|---|---|---|
currency |
ISO 4217 code (EUR, USD, ...) | |
due_date |
||
invoice_date |
||
invoice_number |
||
line_items |
Array<LineItem> | |
payment_method |
||
payment_reference |
IBAN or payment reference | |
subtotal |
||
total_amount |
||
vat_amount |
||
vendor_address |
||
vendor_name |
||
vendor_tax_id |
SIRET / tax ID |
LineItem¶
| Name | Type | Description |
|---|---|---|
amount |
||
description |
||
quantity |
||
unit_price |
||
vat_rate |
ReceiptAnalysisItem¶
| Name | Type | Description |
|---|---|---|
authenticity |
Signaux d'authenticité faibles et contournables — une aide au tri humain, jamais une preuve ni un verdict. `null` signifie que l'authenticité n'a pas pu être évaluée (fichier rejeté avant analyse, ou échec du fournisseur de signaux), jamais qu'aucun signal n'a été trouvé : l'absence de signal se lit sur un objet présent dont `signals` est vide. | |
confidence |
||
data |
||
error |
||
filename |
string | |
findings |
Array<FindingOut> | Écarts de cohérence interne et de politique de dépenses. Une évaluation, jamais une autorisation : aucun reçu n'est rejeté. |
index |
integer |
ReceiptAnalysisResponse¶
| Name | Type | Description |
|---|---|---|
analysed_at |
string(date-time) | |
duplicate_groups |
Array<DuplicateGroupOut> | |
items |
Array<ReceiptAnalysisItem> | |
policy_is_default |
boolean |
ReceiptData¶
| Name | Type | Description |
|---|---|---|
currency |
||
line_items |
Array<LineItem> | |
payment_method |
||
receipt_date |
||
receipt_time |
Heure du ticket, si imprimée | |
subtotal |
||
total_amount |
||
vat_amount |
||
vat_breakdown |
Array<VatBreakdownEntry> | Ventilation par taux ; vat_amount reste le total |
vendor_address |
||
vendor_name |
ResumeData¶
| Name | Type | Description |
|---|---|---|
certifications |
Array<Certification> | |
diplomas |
Array<Diploma> | |
email |
||
experiences |
Array<Experience> | |
firstname |
||
languages |
Array<string> | |
lastname |
||
linkedin |
||
location |
||
phone |
||
skills |
Array<string> |
RibData¶
| Name | Type | Description |
|---|---|---|
account_number |
Numéro de compte (11 chars) | |
agency_code |
Code guichet (5 digits) | |
bank_address |
Domiciliation / agency address | |
bank_name |
||
bic |
||
holder_name |
Account holder as printed (titulaire) | |
iban |
IBAN without spaces | |
rib_key |
Clé RIB (2 digits) |
SchemaField¶
| Name | Type | Description |
|---|---|---|
description |
||
name |
string | |
type |
string |
SchemaInfo¶
| Name | Type | Description |
|---|---|---|
document_type |
string | |
fields |
Array<SchemaField> |
TextSource¶
Type: string
ValidationError¶
| Name | Type | Description |
|---|---|---|
ctx |
||
input |
||
loc |
Array<> | |
msg |
string | |
type |
string |
VatBreakdownEntry¶
| Name | Type | Description |
|---|---|---|
amount |
Montant de TVA pour ce taux | |
rate |
Taux en pourcentage, ex. 20.0 ou 5.5 | |
taxable_base |
Base imposable pour ce taux |