GET /preflight/supplier
Runs every check on a counterparty, in one call, before your agent onboards it, pays it or invoices it:
| Block | Question it answers | Source |
|---|---|---|
identity | Does it exist, and is it still active? | INSEE Sirene, or GLEIF |
events | Insolvency, deregistration, sales — what has been gazetted? | BODACC |
vat | Is its EU VAT number valid right now? | VIES, live |
peppol | Can it receive an e-invoice? | Peppol directory |
group | Who declares control over it? | GLEIF Level 2 |
name_screening | Is the company itself designated? | OFAC SDN & Consolidated, EU FSF, UN |
parent_screening | Is its ultimate parent designated? | the same lists |
bank | Is its IBAN payable? (only when you pass iban) | /preflight/payment |
It returns one verdict — ok, review, stop or insufficient_coverage —
with every reason attached to the block it came from, and each block’s full
answer, in the exact shape of the matching standalone endpoint, next to it.
x402 golden rule: the agent pays for the answer to its question. A
counterparty in liquidation is a useful answer → 200 with a motivated
stop. A well-formed identifier that no register knows is a 404, unbilled:
no empty pre-flight is ever billed.
The rule that makes the verdict worth reading
okis impossible while any block isunavailable. A check that did not happen never passes.
A French company with no LEI has no publishable control chain — so
parent_screening cannot run either, and the answer is
insufficient_coverage, never ok. That is a structural limit of the LEI
reference, stated as such, not an outage and not a silence.
Two distinctions do all the work here, and the composite never blurs them:
not_applicableis an answer;unavailableis a gap. “GLEIF publishes that there is no parent above this entity” is an answer. “We could not establish the control chain” is a gap — and only the gap forbidsok.- A gap is not a signal. A VAT number that VIES could not check is a gap; a VAT number the member state firmly answers as invalid is a signal, and it weighs on the verdict.
The verdict is always exactly the maximum severity among the reasons, and every reason carries its block, a stable code and a detail when there is one — so you can recompute the verdict from the blocks instead of taking it on trust.
One call in place of several
This endpoint is not priced at the catalog’s flat per-call rate, and that is
deliberate: one call runs seven checks — eight with an IBAN. It performs the
work of the /company/* and /screen/entity calls, in one round-trip and
one x402 settlement, and adds what no sequence of unit calls gives you:
the screening of the ultimate parent, which an endpoint-by-endpoint review
misses, and the decision table that turns eight independent answers into one
verdict with an explicit rule for what happens when a check could not run.
No price is written on this page. The gateway’s
/catalog is the single source of truth for every amount,
including the unit endpoints, so you can compare them there.
Scope and limits
Every response carries this sentence in data.limits, verbatim:
This verdict is a deterministic decision table over sourced, dated facts from public registers; it is not a credit opinion, a risk score or a recommendation to act. ‘ok’ only means that every requested check was answered and none of them raised a signal, on the data served (see each block’s provenance and coverage). Parent screening covers the declared accounting consolidation parent, never the beneficial owner.
In particular:
- Control chain ≠ beneficial ownership. GLEIF Level 2 publishes the accounting consolidation parent, self-declared, with no percentage. It is not a UBO under AML/KYC rules, and the absence of a declared parent is not evidence of an absence of control.
- No search by name. The entry key is a SIREN or an LEI.
- No credit score, no financial statements, no directors.
Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
siren | string | one of | 9-digit SIREN, Luhn-checked |
lei | string | one of | 20-character LEI (ISO 17442 check digits) |
iban | string | no | Adds the bank block. Absent means the block is absent — not an empty block |
vat_number | string | no | VAT number of any member state; absent, it is derived from the anchoring SIREN |
screen_parent | bool | no | Screen the ultimate parent too; default true |
Give exactly one entity key, siren or lei — zero or two is a 400.
Both keys pre-flight the same company. An lei= entry whose GLEIF record
declares a SIREN that really exists in the register reopens all the French
blocks (events, Peppol, derived VAT); query.resolved_siren says which one. A
foreign entity with no French registration gets those blocks as
not_applicable — never as a gap, and never as a silent empty.
screen_parent=falsedoes not block anok. Your explicit choice makes the blocknot_requested, which is not a coverage gap. Not knowing whether a parent exists is a different thing: that isunavailable, and it does forbidok.
200 response — UnifiedResponse
{
"data": {
"query": { "key": "siren", "value": "…", "screen_parent": true, "iban_submitted": false },
"subject": { "name": "…", "siren": "…", "lei": "…" },
"verdict": "ok",
"verdict_reasons": [],
"blocks": { "identity": { … }, "events": { … }, … },
"limits": "This verdict is a deterministic decision table …"
},
"provenance": {
"source": "insee-sirene",
"fetched_at": "2026-07-30T19:10:02Z",
"freshness": { "kind": "snapshot", "as_of": "2026-06-30T00:00:00Z" }
}
}
The root provenance reflects the identity foundation — the register the
subject was resolved from. The dates that matter for each check are on each
block: the snapshots are dated differently and the VAT check is live.
Shape of a block
{
"coverage": "complete",
"data": { … },
"provenance": { "source": "dila-bodacc", "fetched_at": "…", "freshness": { "kind": "snapshot", "as_of": "2026-07-26T00:00:00Z" } }
}
A block that is not complete carries neither data nor provenance —
only its coverage and a short stable reason. The gap is stated, never
filled.
coverage | Meaning | Effect on the verdict |
|---|---|---|
complete | The question got its answer | none |
unavailable | It did not — missing dataset, internal service unreachable, member state down (degraded data may still be served) | forbids ok |
not_applicable | There was nothing to check — no French register for a foreign entity, no declared parent, no VAT number | none |
not_requested | You waived the check (screen_parent=false) | none |
Verdicts and reason codes
| Verdict | Rule | Block | code |
|---|---|---|---|
stop | Legal unit ceased (Sirene) | identity | entity_ceased |
stop | Entity INACTIVE (GLEIF) | identity | entity_inactive |
stop | Published deregistration | events | deregistered |
stop | Open insolvency proceeding with no published closure | events | open_insolvency_announcement |
stop | Sanctions hit on the company | name_screening | sanctions_hit |
stop | Sanctions hit on the ultimate parent | parent_screening | parent_sanctions_hit |
stop | The bank check itself returned stop | bank | bank_preflight_stop |
review | Sanctions weak_hit on the company / on the parent | name_screening / parent_screening | weak_sanctions_hit / parent_weak_sanctions_hit |
review | VAT number firmly answered invalid by the member state | vat | vat_number_invalid |
review | Gazetted legal event less than 365 days old | events | recent_legal_event |
review | Subject’s jurisdiction under FATF counter-measures | identity | high_risk_jurisdiction |
review | Parent’s jurisdiction under FATF counter-measures | group | parent_high_risk_jurisdiction |
review | LEI registration LAPSED | group | lei_registration_lapsed |
review | The bank check itself returned review | bank | bank_preflight_review |
insufficient_coverage | No signal, but at least one block is unavailable | the block concerned | coverage_unavailable (detail = its reason) |
ok | No signal and full coverage on every requested block | — | — |
Examples
All four examples below are captured from the production service, on the
snapshots dated in their own blocks (Sirene 2026-06-30, BODACC 2026-07-26,
Peppol directory 2026-07-28, GLEIF 2026-07-29, designation lists
2026-07-28; the VAT check is live).
ok — every requested check answered, none of them raised a signal
GET /preflight/supplier?siren=542107651
{
"query": { "key": "siren", "value": "542107651", "screen_parent": true, "iban_submitted": false },
"subject": { "name": "ENGIE", "siren": "542107651", "lei": "LAXUQCHT4FH58LRZDY46" },
"verdict": "ok",
"verdict_reasons": [],
"blocks": {
"identity": {
"coverage": "complete",
"data": { "siren": "542107651", "name": "ENGIE", "status": "active", "legal_form": { "code": "5599", "label": "SA à conseil d'administration (s.a.i.)" }, "…": "…" },
"provenance": { "source": "insee-sirene", "freshness": { "kind": "snapshot", "as_of": "2026-06-30T00:00:00Z" } }
},
"vat": {
"coverage": "complete",
"data": {
"vat_number": "FR13542107651",
"syntax_valid": true,
"status": "valid",
"name": "SA ENGIE",
"derived_from_siren": "542107651",
"checked_at": "2026-07-30T19:10:00Z"
},
"provenance": { "source": "vies + pure-computation", "freshness": { "kind": "live" } }
},
"peppol": {
"coverage": "complete",
"data": { "reachable": false, "participants": [], "coverage": { "directory_as_of": "2026-07-28", "note": "reachability reflects the public Peppol directory export dated directory_as_of, not a live SMP lookup" } },
"provenance": { "source": "peppol-directory", "freshness": { "kind": "snapshot", "as_of": "2026-07-28T00:00:00Z" } }
},
"group": {
"coverage": "complete",
"data": {
"lei": "LAXUQCHT4FH58LRZDY46",
"registration_status": "ISSUED",
"legal_country": "FR",
"ultimate_parent": { "status": "reporting_exception", "link": null, "exception": { "category": "ULTIMATE_ACCOUNTING_CONSOLIDATION_PARENT", "reasons": ["NATURAL_PERSONS"] } },
"limits": "Relationships are self-declared by the entities to GLEIF and describe accounting consolidation …"
},
"provenance": { "source": "gleif", "freshness": { "kind": "snapshot", "as_of": "2026-07-29T00:00:00Z" } }
},
"name_screening": {
"coverage": "complete",
"data": { "query": { "name": "ENGIE", "normalized": "engie" }, "verdict": "no_hit", "hits": [], "lists_screened": [ { "list": "EU-FSF", "entities": 6017 }, { "list": "OFAC-CONS", "entities": 481 }, { "list": "OFAC-SDN", "entities": 19157 }, { "list": "UN", "entities": 1011 } ], "total_matches": 0 },
"provenance": { "source": "ofac-sdn+ofac-consolidated+eu-fsf+un-sc", "freshness": { "kind": "snapshot", "as_of": "2026-07-28T00:00:00Z" } }
},
"parent_screening": { "coverage": "not_applicable", "reason": "no_declared_ultimate_parent_to_screen" }
}
}
parent_screening is not_applicable here, not a gap: GLEIF publishes a
reporting exception — the consolidating parents are natural persons — so there
is no parent name to screen. That is an answer, and an answer does not block
ok.
Note also peppol.reachable: false. Not being registered in the Peppol
directory is a fact about e-invoicing, not a signal about the supplier: it
weighs nothing on the verdict.
review — the parent is the reason this endpoint exists
GET /preflight/supplier?siren=316037753
{
"subject": { "name": "IBM FRANCE FINANCEMENT", "siren": "316037753", "lei": "0XKTQGPTA3P542CII630" },
"verdict": "review",
"verdict_reasons": [
{ "block": "parent_screening", "code": "parent_weak_sanctions_hit", "detail": "partial_tokens" }
],
"blocks": {
"identity": { "coverage": "complete", "data": { "name": "IBM FRANCE FINANCEMENT", "status": "active", "…": "…" } },
"events": { "coverage": "complete", "data": { "events": [], "total": 0, "flags": { "has_open_insolvency_announcement": false, "is_deregistered": false } } },
"vat": { "coverage": "complete", "data": { "vat_number": "FR60316037753", "status": "valid", "name": "SAS IBM FRANCE FINANCEMENT" } },
"group": {
"coverage": "complete",
"data": {
"lei": "0XKTQGPTA3P542CII630",
"legal_country": "FR",
"ultimate_parent": {
"status": "declared",
"link": {
"lei": "VGRQXHF3J8VDLUA7XE92",
"entity": { "legal_name": "INTERNATIONAL BUSINESS MACHINES CORPORATION", "legal_country": "US" },
"relationship_status": "ACTIVE",
"period": { "start": "1988-07-08" }
}
}
}
},
"name_screening": { "coverage": "complete", "data": { "query": { "name": "IBM FRANCE FINANCEMENT" }, "verdict": "no_hit", "hits": [] } },
"parent_screening": {
"coverage": "complete",
"data": {
"query": { "name": "INTERNATIONAL BUSINESS MACHINES CORPORATION", "normalized": "international business machines" },
"verdict": "weak_hit",
"hits": [ { "id": "OFAC-SDN:45091", "list_source": "OFAC-SDN", "match_type": "partial_tokens", "…": "…" } ]
}
}
}
}
The company itself is spotless: active, VAT valid, no gazetted event, no_hit
on the lists. The review comes entirely from one level up — the declared
ultimate parent, screened by name, on a partial token overlap. A weak_hit on
the parent is a review, never a stop: a token overlap is a lead to
check, not a designation.
Another review you will meet often is the gazette: a supplier with a recent
BODACC entry (for instance a sale published on 2026-06-05) comes back
review with recent_legal_event — a change worth reading, not a red flag.
stop — the register says it plainly
GET /preflight/supplier?siren=542097704
{
"subject": { "name": "RECYLEX SA", "siren": "542097704", "lei": "969500N70Q1WX29Z2675" },
"verdict": "stop",
"verdict_reasons": [
{ "block": "events", "code": "open_insolvency_announcement" },
{ "block": "vat", "code": "vat_number_invalid", "detail": "FR48542097704" },
{ "block": "group", "code": "lei_registration_lapsed" }
],
"blocks": {
"identity": { "coverage": "complete", "data": { "name": "RECYLEX SA", "status": "active", "lei": { "registration_status": "LAPSED", "verified_against_sirene": true } } },
"events": {
"coverage": "complete",
"data": {
"events": [
{ "family": "insolvency", "nature": "Dépôt de l'état des créances", "effective_on": "2023-02-23", "published_on": "2024-06-02", "court": "Greffe du Tribunal de Commerce de Paris" },
{ "family": "insolvency", "nature": "Jugement de conversion en liquidation judiciaire", "effective_on": "2022-11-09", "published_on": "2022-12-04", "court": "Greffe du Tribunal de Commerce de Paris" },
{ "family": "insolvency", "nature": "Jugement d'ouverture d'une procédure de redressement judiciaire", "effective_on": "2022-05-05", "published_on": "2022-05-22", "court": "Greffe du Tribunal de Commerce de Paris" }
],
"total": 6,
"flags": { "has_open_insolvency_announcement": true, "is_deregistered": false },
"coverage": { "window": { "from": "2008-01-01", "to": "2026-07-26" } }
},
"provenance": { "source": "dila-bodacc", "freshness": { "kind": "snapshot", "as_of": "2026-07-26T00:00:00Z" } }
},
"vat": { "coverage": "complete", "data": { "vat_number": "FR48542097704", "syntax_valid": true, "status": "invalid" } },
"name_screening": { "coverage": "complete", "data": { "verdict": "no_hit", "hits": [] } },
"parent_screening": { "coverage": "not_applicable", "reason": "no_declared_ultimate_parent_to_screen" }
}
}
Three reasons, most severe first, each attached to its block and each auditable
in the block right below it: the gazette shows the judgments and their courts,
VIES answers invalid on the derived VAT number, GLEIF has let the LEI
registration lapse. Note that Sirene still reports the legal unit as active —
the composite does not reconcile the registers, it reports each one and lets
the most severe fact decide.
insufficient_coverage — clean, but the control chain is unknowable
GET /preflight/supplier?siren=500569405
{
"subject": { "name": "DECATHLON FRANCE", "siren": "500569405", "lei": null },
"verdict": "insufficient_coverage",
"verdict_reasons": [
{ "block": "group", "code": "coverage_unavailable", "detail": "no_lei_declared_for_siren" },
{ "block": "parent_screening", "code": "coverage_unavailable", "detail": "group_unavailable" }
],
"blocks": {
"identity": { "coverage": "complete", "data": { "name": "DECATHLON FRANCE", "status": "active", "legal_form": { "code": "5710", "label": "SAS, société par actions simplifiée" } } },
"events": { "coverage": "complete", "data": { "flags": { "has_open_insolvency_announcement": false, "is_deregistered": false } } },
"vat": { "coverage": "complete", "data": { "vat_number": "FR11500569405", "status": "valid", "name": "SASU DECATHLON FRANCE" } },
"peppol": { "coverage": "complete", "data": { "reachable": false, "participants": [] } },
"group": { "coverage": "unavailable", "reason": "no_lei_declared_for_siren" },
"name_screening": { "coverage": "complete", "data": { "verdict": "no_hit", "hits": [] } },
"parent_screening": { "coverage": "unavailable", "reason": "group_unavailable" }
}
}
Active, VAT valid, nothing in the gazette, nothing on the lists — and still not
ok. No LEI is declared for this SIREN, so the control chain cannot be
established, so the parent cannot be screened. The gap cascades and is
named (group_unavailable), rather than being reported as “no parent”. Most
French companies have no LEI: this verdict is the normal, honest answer for
them, and it tells your agent exactly which question is still open.
Two variants worth knowing
- Entering by
lei=on a foreign entity —?lei=VGRQXHF3J8VDLUA7XE92returns identity from GLEIF andevents,vatandpeppolasnot_applicable(no_french_registration,no_vat_number_to_check). The verdict is decided on what does apply, never dragged down by registers that cannot concern the subject. - Adding
iban=adds abankblock that carries a whole/preflight/paymentanswer — with the register name of the supplier used as the beneficiary name, so the name block of the bank check is genuinely screened rather than skipped.
Errors
| Status | code | Case |
|---|---|---|
| 400 | INVALID_INPUT | Zero or two entity keys, or an uninterpretable screen_parent / VAT number |
| 400 | INVALID_CHECKSUM | siren failing Luhn, or lei failing its ISO 17442 check digits |
| 404 | NOT_FOUND | Well-formed key unknown to the register — unbilled |
| 503 | DATA_UNAVAILABLE | The queried register’s dataset was never ingested |
| 500 | INTERNAL | Internal error (detail logged, not exposed) |
{ "code": "NOT_FOUND", "error": "siren not found in the Sirene register" }
An unusable answer is never billed; a stop, a review and an
insufficient_coverage all are, because all three are answers.
See also
GET /preflight/payment— the same idea on a transfer: IBAN, bank, jurisdiction and beneficiary name, in one call.GET /company/resolve,GET /company/events,GET /company/vat,GET /company/peppol,GET /company/ownershipandGET /screen/entity— the unit checks this endpoint runs, if you would rather orchestrate them yourself.GET /company/report— the same registers assembled as a report, without the verdict.- For agents — discovery surfaces, the live
/catalogand how settlement works.