FR
Copied
Modules

SIRENE company registry

Source module that extracts French companies from the local INSEE SIRENE registry, targeted by activity and geographic zone. France only.

Purpose

Source module: an alternative starting point to scrap that reads companies directly from the official French business registry (INSEE, base SIRENE), instead of Google Maps. Every record comes from a public administrative source, not from a live crawl: no browser, no proxy, no network request leaves the server, since the registry is mirrored locally and refreshed daily from the INSEE flux.

Use it when the request is "companies in this sector", "companies with this NAF code", "companies created recently", or any list that should not go through Google Maps at all.

Inputs

Field Type Required Description
activites string[] yes Activities targeted. Each entry is either a trade in plain language ("plombier", "boulangerie") or a direct NAF code ("43.22A", with or without the dot). A single trade can resolve to several NAF codes: a curated synonym table returns every matching code when one exists, otherwise the closest official label match is kept alone. Codes with no match (neither a valid direct code nor a recognised trade) are dropped with a warning rather than failing the job.
zones string[] yes Zones in France only, same grammar as scrap: a department (code or name), a region (expands internally into one lookup per department), a city with an optional radius ("Toulouse 20km"), a postal code, or "France" for the whole country. A zone that resolves to a foreign country is recognised and skipped with an explicit warning (this source does not cover other countries) rather than surfacing the generic "zone not recognised" error.
etablissements enum: tous | sieges no, default tous sieges restricts the result to registered head offices only.
cree_apres string (YYYY-MM-DD) no, default empty Keeps only companies whose legal unit was registered on or after this date. An invalid format is ignored with a warning rather than failing the job.
effectif_min string no, default empty Minimum headcount band, kept and everything above it. Accepts either an INSEE code ("11") or the exact label used in the tranche_effectif output column ("10 à 19 salariés"). Unrecognised values are ignored with a warning.
stop_at int no, default 5000 Maximum number of companies returned. See Limits.

Request body (trade name, single department):

{
  "activites": ["plombier"],
  "zones": ["31"]
}

Request body (direct NAF code, several activities, headquarters only, region):

{
  "activites": ["43.22A", "boulangerie"],
  "zones": ["Bretagne"],
  "etablissements": "sieges",
  "cree_apres": "2024-01-01",
  "stop_at": 20000
}

If "France" is present alongside other zones, it wins: the job searches the whole country and the other zones become redundant (a log line says so, nothing fails). A region is not kept as a single filter, it is expanded into one lookup per department it contains, logged individually, so progress is visible department by department.

Outputs

Result file: UTF-8 CSV, semicolon delimiter, BOM (Excel-safe). Same standard row shape as every other source module, plus columns specific to SIRENE appended at the end.

Column Type Description
nom string Company name, resolved through a fixed cascade: establishment's signboard (enseigne), then establishment's usual trade name, then legal unit's registered name, then legal unit's usual trade name, then, for a sole trader with none of the above, the owner's own first name and surname. This is why some rows show a person's name instead of a business name: that is the company's official name for an individual entrepreneur, not a data gap.
telephone string Always empty. The official registry carries no contact information.
adresse string Establishment's postal address.
site_web string Always empty, same reason as telephone.
email string Always empty, same reason as telephone.
lien_google_maps string Always empty, kept only for column compatibility with the standard row shape shared across source modules; there is no Google Maps identity to link to here.
note, nb_avis float, int Always empty, same reason as lien_google_maps.
query string The exact activites entry (trade or NAF code) that produced this row, as typed by the caller: the way to tell rows apart when a job targets several activities at once.
siren string 9-digit SIREN of the legal unit.
siret string 14-digit SIRET of the establishment.
code_postal string Postal code.
commune string City name.
naf string NAF code of the establishment, base format ("43.22A").
naf_libelle string Official INSEE label for that NAF code.
tranche_effectif string Human-readable headcount band (e.g. "10 à 19 salariés"), a label, never the raw INSEE band code.
date_creation date Registration date of the legal unit (YYYY-MM-DD).
is_siege "oui" | "non" Whether this establishment is the registered head office.

No phone, no email, no website: by design, not by failure. SIRENE is a legal registry, not a contact directory. Chain legal_data after sirene to get named executives and financials: matching happens on the exact SIRET already present in every row, no name-based fuzzy matching involved.

Duplicates

A company is deduplicated on SIRET within the job: if a region expands into several department lookups, or an establishment would otherwise be counted twice, it is written once.

Lifecycle

Standard job lifecycle, see Jobs & lifecycle. No network access, no proxy, no browser: sirene reads a local SQLite database only, so it runs in the parallel pool rather than the shared multi-proxy queue and can execute alongside a scrap or any other multi-proxy job instead of waiting behind it. Progress is reported every 500 rows written. The output CSV is written even when the job ends with zero matches, for inspection.

Pipeline

Field Value
needs null (source module, no input CSV; a root alongside scrap and import)
produces pois

Downstream chaining is column-driven, not just bucket-driven. The pipeline editor will happily connect sirene to any node accepting pois_any, but every enrichment except legal_data requires a column sirene never populates (site_web, lien_google_maps, telephone or email), and resolves to zero usable rows at run time instead of a design-time error.

Endpoints

sirene is a pipeline root, the same way scrap and import are (see Pipeline orchestration). The full field-level contract, including config_schema and defaults, is served live at GET /api/pipelines/schema under nodes.sirene.

Pipeline node payload:

{
  "type": "sirene",
  "config": {
    "activites": ["plombier"],
    "zones": ["31"],
    "etablissements": "tous",
    "cree_apres": "",
    "effectif_min": "",
    "stop_at": 5000
  }
}

Wire it into a graph and submit through the Pipelines API (POST /api/pipelines).

Direct run, without a pipeline

The module has its own creation route, to run it on its own without building a graph:

POST /api/jobs/sirene
{
  "activites": ["plombier"],
  "zones": ["31"],
  "etablissements": "tous",
  "cree_apres": "",
  "effectif_min": "",
  "stop_at": 5000
}

These are exactly the pipeline node's config fields, and exactly the body POST /api/sirene/estimate expects: the same object estimates the volume and then launches the extraction, with no transformation in between. The response is the standard job object. activites and zones are required, everything else is optional.

Two helper routes come with the module:

GET  /api/sirene/activites?q=<text>   find a NAF code from a trade name
POST /api/sirene/estimate             expected volume before launching

Once a job exists, retrieval is standard regardless of how it was created:

GET /api/jobs/{job_id}
GET /api/jobs/{job_id}/download?format=csv|json|xlsx

Limits

Global quotas: see /docs/concepts/limits. Module-specific:

Limit Value
Default result cap (stop_at) 5000
Hard cap on stop_at 50000. A request above it is never rejected: it is silently compacted to 50000 and a warning is logged.
Geographic coverage France only. A foreign zone is skipped with a warning, not a job failure, as long as at least one French zone in the same request resolves.
Activity coverage NAF rev.2 (2008), 732 sub-classes. Orders of magnitude measured on 2026-09-09: activites: ["43.22A"] (plumbers) restricted to department 31 (Haute-Garonne) matches a little over 1,200 establishments; activites: ["10.71C"] (bakeries) restricted to department 75 (Paris) matches a little over 1,800. These volumes move continuously: the daily INSEE feed opens and closes establishments every day, so an exact count is only true on the day it is taken.

Errors

Scenario Behaviour
activites empty Job fails immediately: no activity given.
Every entry in activites unrecognised (neither a valid NAF code nor a known trade) Job fails: no usable NAF code could be determined.
zones empty Job fails immediately: no zone given.
Every zone in zones invalid, unrecognised, or foreign Job fails: no valid French zone resolved.
One zone among several is foreign or unrecognised That zone is skipped with a warning; the job continues on the remaining zones.
Invalid cree_apres format The date filter is ignored with a warning; the job continues without it.
Unrecognised effectif_min The headcount filter is ignored with a warning; the job continues without it.
stop_at not a number, zero, or negative Falls back to the default (5000) with a warning.
stop_at above 50000 Compacted to 50000 with a warning; the job is never refused for asking too much.
Zero establishments match the resolved filters The job fails with an explanation once resolution completes, after writing the (empty) CSV. Broaden the activity or the zone.

What's next