Skip to content

Last update: October 15, 2026

Doc Trust API

Local port (Docker Compose): 30008 | Repo: solyntek/djinn/services/djinn-doc-trust

Authenticity opinion on a supporting document (bank details slip, receipt, attestation): the answer is consistent, suspicious or inconsistent, with the signals behind it and an explanation.

An evaluation, never an authorisation

The opinion is an indication that calls for a human check. It never authorises or refuses anything by itself: "suspicious" and "inconsistent" mean "to check", not "fake". Files are analysed in memory and never stored.

Endpoints

Method Route Description
GET /health Health check (rules version, trust-list snapshot sequence)
POST /v1/authenticity/analyze Analyse one document

Analyse a document

POST /v1/authenticity/analyze, multipart/form-data, X-API-Key required.

Field Type Rule
file file PDF, PNG, JPEG, TIFF or WEBP, up to 50 MiB; the real type is read from the file signature, not the extension
document_type rib, receipt, attestation, resume, id_card, other Required; selects the rule profile
fields JSON string (object) Optional, up to 16 KiB: fields already extracted from the document (for example by Doc Extract), used to cross-check the content. Values are never logged
curl -X POST https://api.dev.djinn.solyntek.io/v1/authenticity/analyze \
  -H "X-API-Key: your-api-key" \
  -F "file=@rib.pdf" \
  -F "document_type=rib"
{
  "verdict": "suspicious",
  "score": 0.35,
  "signals": [
    {
      "code": "pdf_online_editor",
      "family": "metadata",
      "strength": "strong",
      "message": "Le document a été produit par un éditeur en ligne (Canva).",
      "detail": {"producer": "Canva"}
    }
  ],
  "explanation": "…",
  "rules_version": "2026.10.1",
  "document_sha256": "…",
  "document_type": "rib",
  "analysed_at": "2026-10-05T09:12:44Z"
}

Verdict

Verdict Meaning
consistent No signal calls for a check
suspicious At least one strong signal, or at least two weak ones: to check
inconsistent At least two strong signals from different families: to check first

score goes from 0 to 1. It is a triage indicator (the higher, the more to check), not a probability. A signal has a family (metadata, structure, fonts, image, content, 2ddoc) and a strength (strong, weak, info); two signals from different families are independent. Signal messages are in French and never contain business data (IBAN, amount, name).

Errors

Business errors use {"detail": {"code": "...", "message": "..."}}.

Status Cause
401 Missing or invalid API key
413 File larger than 50 MiB (file_too_large)
422 empty_file, unsupported_type, unreadable_file (encrypted, corrupted or truncated), invalid_fields, or invalid document_type (request validation)
500 The audit event could not be written: no trace, no action

A service that calls Doc Trust must treat any non-200 answer as "not evaluated", never as "no signal".

Interactive reference

Generated on every build from the versioned spec openapi/doc-trust-v1.json (ADR-011) — no route is documented by hand.

Djinn Doc Trust 0.1.0

Avis d'authenticité documentaire par règles (évaluation, jamais autorisation)


Endpoints


GET /health

Health

Description

Health check, sans authentification.

Responses

{
    "status": "string",
    "service": "string",
    "version": "string",
    "rules_version": "string",
    "tsl_sequence": 0,
    "tsl_issued": "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"
        },
        "service": {
            "type": "string",
            "title": "Service"
        },
        "version": {
            "type": "string",
            "title": "Version"
        },
        "rules_version": {
            "type": "string",
            "title": "Rules Version"
        },
        "tsl_sequence": {
            "type": "integer",
            "title": "Tsl Sequence"
        },
        "tsl_issued": {
            "type": "string",
            "title": "Tsl Issued",
            "description": "Date d'émission de la TSL embarquée (AAAA-MM-JJ)."
        }
    },
    "type": "object",
    "required": [
        "status",
        "service",
        "version",
        "rules_version",
        "tsl_sequence",
        "tsl_issued"
    ],
    "title": "HealthResponse",
    "description": "Response for the health check endpoint."
}

POST /v1/authenticity/analyze

Analyze

Description

Avis d'authenticité d'un justificatif (PDF ou image) : évaluation, jamais autorisation.

Le type réel du fichier est lu dans ses octets, pas dans son nom. fields est un objet JSON facultatif (16 Kio max) des champs déjà extraits ; ses valeurs ne sont jamais journalisées.

Input parameters

Parameter In Type Default Nullable Description
X-API-Key header No

Request body

{
    "file": "string",
    "document_type": "rib",
    "fields": 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": {
        "file": {
            "type": "string",
            "contentMediaType": "application/octet-stream",
            "title": "File"
        },
        "document_type": {
            "type": "string",
            "enum": [
                "rib",
                "receipt",
                "attestation",
                "resume",
                "id_card",
                "other"
            ],
            "title": "Document Type"
        },
        "fields": {
            "anyOf": [
                {
                    "type": "string"
                },
                {
                    "type": "null"
                }
            ],
            "title": "Fields"
        }
    },
    "type": "object",
    "required": [
        "file",
        "document_type"
    ],
    "title": "Body_analyze_v1_authenticity_analyze_post"
}

Responses

{
    "verdict": "consistent",
    "score": 10.12,
    "signals": [
        {
            "code": "string",
            "family": "metadata",
            "strength": "info",
            "message": "string",
            "detail": {}
        }
    ],
    "explanation": "string",
    "rules_version": "string",
    "document_sha256": "string",
    "document_type": "rib",
    "analysed_at": "2022-04-13T15:42:05.901Z"
}
⚠️ 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": {
        "verdict": {
            "type": "string",
            "enum": [
                "consistent",
                "suspicious",
                "inconsistent"
            ],
            "title": "Verdict",
            "description": "`consistent` (aucun signal notable), `suspicious` (à vérifier), `inconsistent` (au moins deux signaux forts de familles différentes)."
        },
        "score": {
            "type": "number",
            "maximum": 1.0,
            "minimum": 0.0,
            "title": "Score",
            "description": "Indicateur de tri, pas une probabilité : min(1, 0,35 x signaux forts + 0,1 x signaux faibles). Plus il est haut, plus il y a à vérifier."
        },
        "signals": {
            "items": {
                "$ref": "#/components/schemas/SignalOut"
            },
            "type": "array",
            "title": "Signals"
        },
        "explanation": {
            "type": "string",
            "title": "Explanation"
        },
        "rules_version": {
            "type": "string",
            "title": "Rules Version"
        },
        "document_sha256": {
            "type": "string",
            "title": "Document Sha256"
        },
        "document_type": {
            "type": "string",
            "enum": [
                "rib",
                "receipt",
                "attestation",
                "resume",
                "id_card",
                "other"
            ],
            "title": "Document Type"
        },
        "analysed_at": {
            "type": "string",
            "format": "date-time",
            "title": "Analysed At"
        }
    },
    "type": "object",
    "required": [
        "verdict",
        "score",
        "signals",
        "explanation",
        "rules_version",
        "document_sha256",
        "document_type",
        "analysed_at"
    ],
    "title": "AnalyzeResponse",
    "description": "Avis d'authenticité : une évaluation, jamais une autorisation."
}

{
    "detail": {
        "code": "string",
        "message": "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": {
        "detail": {
            "$ref": "#/components/schemas/ErrorBody"
        }
    },
    "type": "object",
    "required": [
        "detail"
    ],
    "title": "ErrorDetail"
}

{
    "detail": {
        "code": "string",
        "message": "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": {
        "detail": {
            "$ref": "#/components/schemas/ErrorBody"
        }
    },
    "type": "object",
    "required": [
        "detail"
    ],
    "title": "ErrorDetail"
}

Schemas

AnalyzeResponse

Name Type Description
analysed_at string(date-time)
document_sha256 string
document_type string
explanation string
rules_version string
score number Indicateur de tri, pas une probabilité : min(1, 0,35 x signaux forts + 0,1 x signaux faibles). Plus il est haut, plus il y a à vérifier.
signals Array<SignalOut>
verdict string `consistent` (aucun signal notable), `suspicious` (à vérifier), `inconsistent` (au moins deux signaux forts de familles différentes).

Body_analyze_v1_authenticity_analyze_post

Name Type Description
document_type string
fields
file string

ErrorBody

Name Type Description
code string `empty_file`, `file_too_large`, `unsupported_type`, `unreadable_file` ou `invalid_fields`.
message string

ErrorDetail

Name Type Description
detail ErrorBody

HealthResponse

Name Type Description
rules_version string
service string
status string
tsl_issued string Date d'émission de la TSL embarquée (AAAA-MM-JJ).
tsl_sequence integer
version string

SignalOut

Name Type Description
code string
detail Métadonnées techniques seulement (producteur, nombre de révisions...). Jamais une valeur métier (IBAN, montant, nom).
family string
message string Message en français, sans donnée métier.
strength string