Is this SIREN a real, still-active company? INSEE Sirene

An agent holding a SIREN or SIRET gets the official INSEE Sirene identity card in one paid call — legal name, active or ceased status, head office, no account.

By Matthias Begot · · Updated

An agent about to onboard a supplier, book an inbound invoice or release a first payment holds a nine-digit number it did not verify. 394406938 is a well-formed SIREN. So is 394406939 — it just isn’t one. GET /company/resolve turns that number into the official identity card: legal name, active or ceased status, legal form, NAF activity, workforce band, creation date and head-office address, served offline from the INSEE Sirene register under the Etalab open licence. One call, no account, no API key.

The three things worth knowing before wiring it are that a ceased company is a paid answer, that a SIRET resolves to its legal unit and says so, and that a field the register does not carry comes back null with a receipt rather than filled in from somewhere else. Below, each is walked with responses captured from production on 11 August 2026, against the Sirene snapshot dated 2026-07-31.

The identity card, captured

GET /company/resolve?siren=542051180:

{
  "data": {
    "siren": "542051180",
    "name": "TOTALENERGIES SE",
    "acronym": null,
    "natural_person": null,
    "status": "active",
    "legal_form": { "code": "5800", "label": "Société européenne" },
    "main_activity": {
      "code": "70.10Z",
      "label": "Activités des sièges sociaux",
      "nomenclature": "NAFRev2"
    },
    "workforce": { "bracket": "51", "year": 2023 },
    "created_on": "1954-01-01",
    "last_processed_on": "2025-12-06",
    "is_employer": null,
    "social_economy": false,
    "headquarters": {
      "siret": "54205118000066",
      "status": "active",
      "address": {
        "line": "2 PLACE JEAN MILLIER",
        "postal_code": "92400",
        "city": "COURBEVOIE",
        "country": null
      },
      "created_on": "2000-03-22"
    },
    "lei": {
      "lei": "529900S21EQ1BO4ESM68",
      "legal_name": "TotalEnergies SE",
      "entity_status": "ACTIVE",
      "registration_status": "ISSUED",
      "verified_against_sirene": true,
      "total_matches": 1
    },
    "coverage": { "missing": [] }
  },
  "provenance": {
    "source": "insee-sirene",
    "fetched_at": "2026-08-11T15:21:50Z",
    "freshness": { "kind": "snapshot", "as_of": "2026-07-31T00:00:00Z" }
  }
}

The lookup runs against a local store, so there is no network call and no secret at request time — the same property that makes /iban/resolve and /phone/validate answer in milliseconds. The key is a SIREN or a SIRET, never a name: this endpoint serves agents that already hold an identifier off an invoice, a contract or a supplier form.

The lei block appears only when an entity in the GLEIF reference declares this SIREN — a bridge to the global identity, and the entry point to GET /company/lei. It is absent for most French companies, which is a fact about LEIs, not a gap. Note that the GLEIF legal_name sits beside the Sirene name, never in place of it: two self-declared registers, two spellings, neither rewritten with the other.

Roughly half of what you can look up has ceased

status: "ceased" comes back as a 200, and it is billed. That is the whole point: the agent asked “who is this company and is it still trading?”, and “it stopped” is precisely the answer that should halt an onboarding. GET /company/resolve?siren=552100554 returns PEUGEOT SA with status: "ceased", a ceased head office in Vélizy-Villacoublay, and a lei block reading entity_status: "INACTIVE", registration_status: "RETIRED". Two registers agreeing that a famous name is no longer a live counterparty.

This is not an edge case. Probing random check-digit-valid SIRENs against the served snapshot, 80 of the 169 legal units that resolved came back ceased — the register is a historical record, not a directory of going concerns. An integration that treats “found in Sirene” as “safe to pay” has misread the answer by a factor of two.

The register also moves in bulk. INSEE ran a consistency alignment between Sirene and the national business registers on 17–18 June 2026, updating over 260,000 legal units and their establishments, in two successive waves, principally cessations and closures (Insee, Sirene Open Data — actualités). A company an agent resolved as active in May could be correctly ceased in the July snapshot without anything having “broken”.

The v1 identity is the legal unit plus its head office. Hand it a SIRET and three things can happen, each distinguishable without guessing:

InputResult
SIRET of the head officeNormal answer plus is_headquarters: true
SIRET of an existing secondary establishmentAnswer about the parent legal unit, is_headquarters: false, plus coverage.establishment: "resolved_to_legal_unit"
Luhn-valid SIRET whose establishment does not exist404 NOT_FOUND, not billed

GET /company/resolve?siret=54205118000033 — a secondary TotalEnergies establishment — returns the TotalEnergies legal unit with:

"is_headquarters": false,
"coverage": { "establishment": "resolved_to_legal_unit", "missing": [] }

Read that marker before reading the address. The data describes the legal unit and its head office, not the queried establishment’s own record — the v1 store does not carry per-establishment addresses, dates or workforce, and says so rather than quietly serving the head office as though it were the branch on the invoice.

The existence check matters more than it looks. A SIRET’s five-digit NIC means a typo has roughly a one-in-ten chance of passing the checksum; the existence index is what catches the nine other cases.

Checksum failure and non-existence are different answers

Both leave the 200 range, both are unbilled, and an agent must react to them in opposite ways:

GET /company/resolve?siren=394406939
→ 400 { "code": "INVALID_CHECKSUM", "error": "siren failed its checksum (Luhn): likely a typo" }

GET /company/resolve?siren=000000018
→ 404 { "code": "NOT_FOUND", "error": "siren not found in the Sirene register" }

The first says fix your input — one digit off a real number. The second says this key is well-formed and the register has never heard of it, which is the answer for an ERP filler value or a fabricated identifier. Collapsing the two into “lookup failed” throws away the distinction that tells an agent whether to retry or to stop.

There is one documented exception, and it is live: SIRETs on the La Poste prefix 356000000 carry no check-digit control at all. 35600000000051 fails the standard Luhn test and is nonetheless a real establishment — it resolves 200 to LA POSTE with resolved_to_legal_unit. So the checksum is bypassed for that prefix entirely and existence decides alone: 35600000099999 is a 404, never a 400. A rule that would reject genuine identifiers is not a rule worth enforcing.

What the register does not say, it does not invent

The Sirene register has real gaps: records under partial or protected diffusion, fields simply never filled in. Those are served as null and listed in coverage.missing. A live example, an active sole trader:

{
  "siren": "810678904",
  "name": null,
  "natural_person": null,
  "status": "active",
  "legal_form": { "code": "1000", "label": "Entrepreneur individuel" },
  "main_activity": { "code": "68.20A", "label": "Location de logements", "nomenclature": "NAFRev2" },
  "headquarters": {
    "siret": "81067890400030",
    "status": "active",
    "address": { "line": null, "postal_code": null, "city": "PARIS", "country": null }
  },
  "coverage": { "missing": ["name", "headquarters.address"] }
}

The company exists, it is active, and its name and street address are withheld by the register — not missing from the service. An agent reading coverage.missing knows the difference between “no data” and “no answer”, and can escalate to a human instead of concluding the supplier is fake. In the same sample of 169 units, headquarters.address was withheld or unfilled 22 times and name 13 times.

Labels follow the same discipline. legal_form.label and main_activity.label come from embedded INSEE nomenclatures; a code outside them is served with label: null, never an invented wording. That is common on old records: of the 169 sampled, 123 carried an activity code in NAFRev2, but 25 were still in NAF1993, 10 in NAFRev1 and 11 in the 1970s-era NAP — 46 of them with a null label. Which is exactly why main_activity.nomenclature is a field and not a footnote.

Store the nomenclature, because it is about to change

From 1 January 2027, NAF 2025 becomes the reference nomenclature for APE codes, approved by décret n° 2025-736 du 31 juillet 2025. INSEE is explicit about the blast radius: at that date every active legal unit in the Sirene register and its establishments will have a modified APE code (Insee, Vers une nouvelle nomenclature : la NAF 2025).

An agent that stored "70.10Z" alone has stored something that will silently mean a different thing. An agent that stored code, nomenclature and provenance.freshness.as_of together can still explain, in 2028, what it knew and when.

Billing and failure modes

CaseResult
Company found — including ceased200, billed
SIRET of a secondary establishment, resolved to its legal unit200, billed
Fields withheld by the register, listed in coverage.missing200, billed
Both or neither of siren / siret, malformed identifier400 INVALID_INPUT, not billed
Well-formed identifier failing its Luhn check400 INVALID_CHECKSUM, not billed
Well-formed identifier unknown to the register404 NOT_FOUND, not billed
Store not yet ingested503 DATA_UNAVAILABLE, not settled

The line is the same one the rest of the catalog draws: the agent pays for the answer to its question, and an absence of activity is an answer. A key the register has never seen is not — nobody should pay to learn their input was fiction.

Freshness is declared, never faked. Answers carry freshness.kind: "snapshot" with the end-of-month as_of of the Sirene stock that backed them; INSEE publishes a monthly stock file, and a missed refresh means the last good snapshot keeps being served under its honest date. Stale data is never turned into a 5xx.

Wiring it up

  1. Branch on status before anything else. active and ceased are both 200s. Only one of them should let a payment through.
  2. Check coverage before trusting a null. missing tells you the register withheld a field; establishment tells you a SIRET was resolved upward to its legal unit.
  3. Keep freshness.as_of with the record. “On what basis did the agent onboard this supplier in August 2026” is answerable only if the snapshot date was stored beside the verdict.
  4. Treat 400 and 404 as distinct branches. Retry after fixing the input; stop after a NOT_FOUND.
  5. Discover, then pay. The 402 → pay → replay cycle is walked with runnable snippets in the Quickstart; the machine discovery surfaces are described in For agents.

Identity is one question among several. The SIREN you just resolved is also the key to /company/vat (is the intra-EU VAT number valid today), /company/events (has an insolvency announcement been published), /company/peppol (can this company actually receive the e-invoice you are about to send — which becomes an operational question for every VAT-registered French business from 1 September 2026, when receiving structured e-invoices becomes mandatory), and /company/ownership (who consolidates it). If you would rather buy the whole picture in a single settlement instead of orchestrating the family yourself, GET /company/report bundles them by SIREN with provenance per block, and /preflight/supplier turns the bundle into a one-call onboarding verdict. The identity of an issuer read off an inbound invoice starts at /invoice/read.

Every amount and every accepted settlement rail lives in the gateway’s /catalog, which is the single source of truth — no price appears in this article.

Two limits to keep in view. There is no search by name: the key is an identifier, and no fuzzy matching will be added, because a near-match wearing an official register’s authority is a guess. And this is identity, not risk — no score, no rating, no enrichment from unofficial sources. Naming a counterparty is not screening it; that is /screen/entity for the name and /iban/screen for the account.

The captures above are snapshot-dated illustrations, not a contract: a monthly refresh moves a status, a diffusion request withholds a name, an establishment closes. Only the rules are guaranteed — one key per call, a ceased company served as a ceased company, a withheld field named rather than invented, and an unanswerable request never billed. The full parameter and field contract is on the GET /company/resolve documentation.