# Can this company receive your e-invoice? A Peppol participant lookup > Before an agent sends an e-invoice, GET /company/peppol returns the participant identifiers and accepted document types from a dated Peppol directory export. Published 2026-08-12 · Updated 2026-08-15 · HTML version: https://invoket.com/blog/can-this-company-receive-your-e-invoice --- An agent that has just produced a conformant e-invoice still has one question left before it sends anything: **can the counterparty actually receive it, at which address, and in which format?** [`GET /company/peppol`](/docs/api/company-peppol) answers it from the ingested public export of the Peppol directory — every participant identifier a company is known under, each with its own declared document types. "Not registered" is a **paid, dated `200`**, because the agent pays for a **directory lookup that ran**, not for a "yes". This article walks the endpoint and its boundaries, with captures taken from production on 12 August 2026, against a directory export dated 11 August 2026. ## Why this became a pre-send check in 2026 The French e-invoicing reform makes the question operational rather than academic. Per [impots.gouv.fr](https://www.impots.gouv.fr/professionnel/je-decouvre-la-facturation-electronique), the calendar is: | Date | Obligation | Who | |---|---|---| | 1 September 2026 | **receive** e-invoices through an approved platform | every VAT-liable business, whatever its size | | 1 September 2026 | **issue** e-invoices | large and mid-cap companies | | 1 September 2027 | **issue** e-invoices | SMEs, small businesses, micro-enterprises | The asymmetry is the interesting part. From September 2026 the *reception* side is universal while the *issuing* side is not, so an agent issuing invoices on behalf of a large company spends a year sending documents to counterparties who are obliged to receive them but not yet to send any. Whether a given counterparty is addressable, and under which identifier, stops being a one-time onboarding detail and becomes a **per-send question**. That is visible in the data. In the export we serve, the French reform identifiers registered in **June and July 2026** are everywhere: companies were still declaring their routing addresses weeks before the deadline. A reachability answer cached at onboarding time would already be wrong. ## What the endpoint reads — and what it does not The answer is served **offline**, from an ingested copy of the **complete public Peppol directory export**: over six million participants and tens of millions of declared document types, at the date of that export. Every response carries the date twice, in `coverage.directory_as_of` and in `provenance.freshness.as_of`. Three things it is deliberately not: - **Not a live SMP lookup.** A registration or deregistration that happened after the export is invisible. The response says so in `coverage.note` rather than leaving you to assume real time. - **Not the French *annuaire central*.** France's own directory of VAT-liable businesses and their invoicing addresses, operated on the public portal, is a separate register. Peppol reachability is a strong, checkable signal about addressability on the Peppol network — it is not a statement about a company's compliance with the French mandate. - **Not a regulatory opinion.** Absent from the directory says nothing about whether a company is legally obliged to do anything. ## One SIREN, several addresses A French company is routinely registered under **several** Peppol identifiers at once, each with its own declared document types. A `siren=` query returns them all — that is the point of the French index. `GET /company/peppol?siren=380129866` (Orange; document types abridged): ```json { "data": { "reachable": true, "participants": [ { "id": "0225:380129866", "scheme": "0225", "value": "380129866", "country": "FR", "names": ["Dickinson LLC_Sage_Company_FUll_Name"], "registered_on": "0001-01-01", "document_types": [ { "identifier": "urn:oasis:names:specification:ubl:schema:xsd:Invoice-2::Invoice##urn:cen.eu:en16931:2017#compliant#urn:peppol:france:billing:cius:1.0::2.1", "display_name": "France UBL Invoice CIUS", "label": "invoice" }, { "identifier": "urn:peppol:doctype:pdf+xml##urn:cen.eu:en16931:2017#conformant#urn:peppol:france:billing:Factur-X:1.0::D22B", "display_name": "France Factur-X", "label": null } ] }, { "id": "0225:380129866_achatpub_507807949", "scheme": "0225", "value": "380129866_achatpub_507807949", "country": "FR", "names": ["ORANGE"], "registered_on": "0001-01-01", "document_types": ["…"] }, { "id": "0225:380129866_reserve_pilote", "scheme": "0225", "value": "380129866_reserve_pilote", "country": "FR", "names": ["Orange SA"], "registered_on": "2026-07-05", "document_types": ["…"] } ], "company": { "name": "ORANGE", "natural_person": null, "status": "active" }, "coverage": { "directory_as_of": "2026-08-11", "note": "reachability reflects the public Peppol directory export dated directory_as_of, not a live SMP lookup" } }, "provenance": { "source": "peppol-directory", "fetched_at": "2026-08-12T06:49:52.426422654Z", "freshness": { "kind": "snapshot", "as_of": "2026-08-11T00:00:00Z" } } } ``` Scheme `0225` is **`FR:CTC`**, "FRCTC Electronic Address", issued by AIFE and defined in the [Peppol participant identifier scheme code list](https://docs.peppol.eu/edelivery/codelists/) as an alphanumeric value of up to 130 characters. That length allowance is exactly what the suffixes above use: a single legal entity exposes **routing sub-addresses** for distinct flows. In the same export, Michelin publishes `_fact`, `_autofact` and `_ignoauto`; Dassault Systèmes publishes `_ndf`. These are the counterparty's own internal routing, declared publicly. Note also the fidelity of the relay. The bare-SIREN record declares its name as `"Dickinson LLC_Sage_Company_FUll_Name"` — a software template left in a real production registration — and `registered_on: "0001-01-01"`. Both are relayed **as-is, never corrected**, while the Sirene echo in `data.company` carries the official legal name. An agent gets the declaration and the register side by side, and can see they disagree. ## You cannot construct a CTC address — you have to read it The suffix is not derivable from the SIREN. BNP Paribas, in the same export, is reachable under **two** identifiers that differ only by a repeated prefix: ``` 0225:662042449_bnpp1capp 0225:662042449_662042449_bnpp1capp ``` Both resolve, both carry the same declared name and the same eight document types. Any agent that "builds" a CTC identifier by concatenating a SIREN with a guessed suffix is inventing an address; any agent that only ever tries the bare SIREN will miss the sub-address a counterparty actually reads. Look it up, then address what the directory returned. ## `reachable: true` does not mean "will accept your invoice" This is the trap worth stating loudly: reachability is about the **participant**, acceptance is about the **document type**. The two answers live in different fields, and they disagree more often than you would expect. EQUIPTEC is registered twice. Its SIRET identifier under scheme `0009` accepts **only** Peppol Invoice Response messages — no invoice at all: ``` GET /company/peppol?participant=0009:33328563300033 → reachable: true, 2 document types, all "application-response" ``` Its `0225` identifier accepts UBL and CII invoices plus credit notes. Same company, same call, two very different answers to "can I send an invoice here?". The pattern is not French-specific: the Norwegian public agency `0192:991825827` is reachable with eleven declared document types, nine of them `innbyggerpost` (digital post to citizens) and only one an invoice. So the decision rule for an agent is: `reachable` selects **candidate** addresses, `document_types` selects **the one to send to**. Each entry carries its full Peppol document type `identifier`, the `display_name` as declared, and a short `label` derived at ingestion (`invoice`, `credit-note`, …) — `null` when it cannot be derived, as with `"France Factur-X"` above. A label is **never invented**: if you need certainty, match on `identifier`, which is the normative string. ## "Not registered" is a paid, dated answer A well-formed identifier absent from the directory returns `200 reachable: false`, billed. Carrefour, on the export of 11 August 2026: ```json { "data": { "reachable": false, "participants": [], "company": { "name": "CARREFOUR", "natural_person": null, "status": "active" }, "coverage": { "directory_as_of": "2026-08-11", "note": "reachability reflects the public Peppol directory export dated directory_as_of, not a live SMP lookup" } }, "provenance": { "source": "peppol-directory", "fetched_at": "2026-08-12T06:50:06.181287944Z", "freshness": { "kind": "snapshot", "as_of": "2026-08-11T00:00:00Z" } } } ``` That is a complete answer to the question asked: **no, as of the export date**. The agent now knows to fall back to another channel instead of emitting a document into a void. And the Sirene echo makes the distinction explicit — a large, active company that simply is not in this directory. Absence from a directory is not absence from reality, which is why it is never a `404`. ## The one 404: unknown input, not a missing answer Both French input forms are checked against the **Sirene register** before the directory is read. A Luhn-valid SIREN that INSEE never assigned is a `404 NOT_FOUND`, **not billed**, with the same message as [`GET /company/resolve`](/docs/api/company-resolve): | Request | Result | |---|---| | `?siren=380129866` | `200 reachable: true`, billed | | `?siret=38012986648625` (head office) | `200`, same three identifiers — a SIRET is matched by its SIREN prefix | | `?siren=652014051` | `200 reachable: false`, billed — real company, absent from the directory | | `?siren=123456782` | `404 NOT_FOUND`, unbilled — Luhn passes, names nobody | | `?siren=000000000` | `404 NOT_FOUND`, unbilled | | `?siren=…&participant=…` | `400 INVALID_INPUT` — exactly one of the three | | `?participant=0225380129866` | `400 INVALID_INPUT` — must be `scheme:value` | | `?participant=022:380129866` | `400 INVALID_INPUT` — scheme must be a 4-digit ISO 6523 ICD | | `?siret=38012986600628` | `400 INVALID_CHECKSUM` — fails Luhn, probably a typo | The rule behind the table: **"unknown" and "known but unregistered" are different answers, and only the second one is worth paying for.** Existence is one single truth across the service — no route can bill an answer for an input another route calls unknown. ## Cross-border: `participant=` names any country `siren=` and `siret=` query the French index. `participant=` is an exact lookup on a full Peppol identifier, in **any** country, and is never subject to the Sirene existence check — there is no French register entry to verify. In a sweep across the export it resolved participants in Norway, Belgium, Denmark, Germany, the Netherlands and Austria as readily as French ones. It is also the only way to reach an identifier whose embedded number would fail a French checksum: the Monegasque SIREN `000126010` (ENERTECH MONACO) has leading zeros and does not pass Luhn, so it is queryable **only** as `participant=0002:000126010`. ## Where it sits in an agent's invoicing loop Discovery and settlement are the standard x402 loop from [the quickstart](/docs/quickstart) and [for agents](/docs/for-agents): call, receive a `402` carrying the terms, pay, replay. The sequencing around it: 1. **Check the counterparty is addressable.** This endpoint. Read `participants[]`, pick the identifier whose `document_types` include what you are about to send, and keep `coverage.directory_as_of` with the decision. 2. **Check the tax identity.** [`GET /company/vat`](/docs/api/company-vat) validates the intra-EU VAT number live against VIES — the other pre-invoicing question about the same counterparty, and the one that decides the VAT treatment. 3. **Produce the document.** [`POST /invoice/generate`](/docs/api/invoice-generate) emits a guaranteed EN 16931-conformant invoice, with `ruleset=peppol` when the target is a Peppol BIS Billing 3.0 flow. If the document came from elsewhere, [`POST /invoice/validate`](/docs/api/invoice-validate) gives the deterministic verdict on it first — that judges the **document**, this endpoint judges the **participant**. If the agent wants identity, legal events, VAT and reachability in a single settlement rather than several, [`GET /company/report`](/docs/api/company-report) composes them by SIREN, each block carrying its own provenance. The live [`/catalog`](/docs/for-agents) is authoritative for the endpoint listing and pricing — never hardcode either. ## Limits, stated plainly - **The answer is a photo at the export date.** No live SMP lookup in v1. Read `coverage.directory_as_of` and decide whether that is fresh enough for what you are about to send. - **`names` and `registered_on` are the participants' own declarations**, relayed as-is. `0001-01-01` and templated company names are real values in the public export, not errors on our side. - **Reachable is not compliant, and not obliged.** The endpoint states a directory fact. It is not the French *annuaire central* and carries no view on anyone's legal obligations. - **`label` may be `null`.** The normative value is the full document type `identifier`; the short label is a convenience derived at ingestion and never guessed. - **The Sirene identity echo covers French companies** present in the Sirene stock, and is never attempted on `participant=` input. A missing echo is explained in `coverage.identity`, never an error. ## See also - [`GET /company/peppol`](/docs/api/company-peppol) — full parameters, response fields and error codes. - [`GET /company/vat`](/docs/api/company-vat) — live VIES validation of the counterparty's intra-EU VAT number. - [`GET /company/resolve`](/docs/api/company-resolve) — the identity card behind a SIREN or SIRET. - [`POST /invoice/generate`](/docs/api/invoice-generate) — produce the EN 16931 document once the address is confirmed. - [`POST /invoice/validate`](/docs/api/invoice-validate) — deterministic EN 16931 verdict, including the Peppol BIS Billing 3.0 pack. - [Quickstart](/docs/quickstart) — the `402` → pay → replay loop end to end.