Aller au contenu

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

curl -X POST http://localhost:30002/v1/extract \
  -H "X-API-Key: votre-cle-locale" \
  -F "file=@cv.pdf" \
  -F "document_type=resume"
curl -X POST https://api.dev.djinn.solyntek.io/v1/extract \
  -H "X-API-Key: your-api-key" \
  -F "file=@cv.pdf" \
  -F "document_type=resume"
{
  "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

{
    "status": "string",
    "version": "string"
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "properties": {
        "status": {
            "type": "string",
            "title": "Status",
            "default": "ok"
        },
        "version": {
            "type": "string",
            "title": "Version",
            "default": "0.2.0"
        }
    },
    "type": "object",
    "title": "HealthResponse",
    "description": "Response model for the health check endpoint."
}

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

[
    {
        "document_type": "string",
        "fields": [
            {
                "name": "string",
                "type": "string",
                "description": null
            }
        ]
    }
]
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "type": "array",
    "items": {
        "$ref": "#/components/schemas/SchemaInfo"
    },
    "title": "Response Schemas V1 Schemas Get"
}

{
    "detail": [
        {
            "loc": [
                null
            ],
            "msg": "string",
            "type": "string",
            "input": null,
            "ctx": {}
        }
    ]
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "properties": {
        "detail": {
            "items": {
                "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
        }
    },
    "type": "object",
    "title": "HTTPValidationError"
}

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

{
    "file": "string"
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body
{
    "properties": {
        "file": {
            "type": "string",
            "contentMediaType": "application/octet-stream",
            "title": "File"
        }
    },
    "type": "object",
    "required": [
        "file"
    ],
    "title": "Body_extract_v1_extract_post"
}

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
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

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

{
    "detail": [
        {
            "loc": [
                null
            ],
            "msg": "string",
            "type": "string",
            "input": null,
            "ctx": {}
        }
    ]
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "properties": {
        "detail": {
            "items": {
                "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
        }
    },
    "type": "object",
    "title": "HTTPValidationError"
}

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

{
    "files": [
        "string"
    ]
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the request body
{
    "properties": {
        "files": {
            "items": {
                "type": "string",
                "contentMediaType": "application/octet-stream"
            },
            "type": "array",
            "title": "Files"
        }
    },
    "type": "object",
    "required": [
        "files"
    ],
    "title": "Body_extract_batch_v1_extract_batch_post"
}

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
    }
]
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "type": "array",
    "items": {
        "$ref": "#/components/schemas/ExtractionResult"
    },
    "title": "Response Extract Batch V1 Extract Batch Post"
}

{
    "detail": [
        {
            "loc": [
                null
            ],
            "msg": "string",
            "type": "string",
            "input": null,
            "ctx": {}
        }
    ]
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "properties": {
        "detail": {
            "items": {
                "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
        }
    },
    "type": "object",
    "title": "HTTPValidationError"
}

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
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

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."
}

{
    "detail": [
        {
            "loc": [
                null
            ],
            "msg": "string",
            "type": "string",
            "input": null,
            "ctx": {}
        }
    ]
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "properties": {
        "detail": {
            "items": {
                "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
        }
    },
    "type": "object",
    "title": "HTTPValidationError"
}

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
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

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
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

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."
}

{
    "detail": [
        {
            "loc": [
                null
            ],
            "msg": "string",
            "type": "string",
            "input": null,
            "ctx": {}
        }
    ]
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "properties": {
        "detail": {
            "items": {
                "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
        }
    },
    "type": "object",
    "title": "HTTPValidationError"
}

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

{
    "files": [
        "string"
    ],
    "categories": null
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

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
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

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."
}

{
    "detail": [
        {
            "loc": [
                null
            ],
            "msg": "string",
            "type": "string",
            "input": null,
            "ctx": {}
        }
    ]
}
⚠️ This example has been generated automatically from the schema and it is not accurate. Refer to the schema for more information.

Schema of the response body
{
    "properties": {
        "detail": {
            "items": {
                "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
        }
    },
    "type": "object",
    "title": "HTTPValidationError"
}

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