French company data as JSON or CSV: the recherche-entreprises (SIRENE) API, its limits, a Python example and a free sample
How to pull French company records from the official open API yourself, which limits and filter traps to expect, what to do about directors and sole traders under the GDPR, and when a normalized feed is worth paying for.
The short version
- France publishes company data as open data (INSEE's SIRENE register, the RNE trade register and more). The official, free, keyless search API is recherche-entreprises.api.gouv.fr:
GET /search, JSON out, maintained by the Annuaire des Entreprises team. - The rules that matter: 7 requests per second per IP (HTTP 429 above), 25 results per page and a 10,000-result window, and exact NAF codes only (no prefixes, no NAF 2025). Location filters match any establishment, not just the head office.
- The response includes named directors who are natural persons (name, first names, birth date). That is personal data under the GDPR. The sample on this page has none, and no sole traders either, because a sole trader's business name is a person's name.
1. The recherche-entreprises API
Base URL: https://recherche-entreprises.api.gouv.fr. The interactive documentation is at /docs/ and the OpenAPI file at /openapi.json (it declares API version 1.0.0 and the MIT licence for the API software). No key or login.
curl -s "https://recherche-entreprises.api.gouv.fr/search?q=buffalo+grill&per_page=1"
Limits and errors, as we saw them on 5 November 2026
- Rate limit: 7 requests per second per IP, and 30 per second per ASN (the docs warn that public clouds will probably hit the ASN limit). Above it the server answers
HTTP 429. The docs call these maximums, not guaranteed throughput. per_pageis 1 to 25.per_page=26returnsHTTP 400with the French message "indiquer un paramètre per_page entre 1 et 25". The default is 10.- 10,000 results at most per query.
page * per_pagemust not exceed 10,000, andtotal_resultsitself is capped:q=boulangeriereturnedtotal_results: 10000. Page 401 withper_page=25isHTTP 400. To go beyond, split the query by department, NAF code, size band or legal form. - At least one search parameter is mandatory (
HTTP 400, "Veuillez indiquer au moins un paramètre de recherche"). The free-textqneeds at least 3 characters. - Errors are JSON with a single key
erreur, in French.
Filters
| Goal | Parameter | Trap |
|---|---|---|
| Activity | activite_principale=62.01Z,62.02A | Exact NAF rev. 2 codes only. 56.1 returns HTTP 400 and the error lists the valid codes. No prefix search, and NAF 2025 codes are not accepted (the response has both: activite_principale and activite_principale_naf25). |
| Location | departement, region, code_postal, code_commune | Matches companies with any establishment there; the head office can be elsewhere. |
| Size | tranche_effectif_salarie, categorie_entreprise (PME, ETI, GE) | Workforce band codes, not numbers. |
| Status and form | etat_administratif=A (active) or C (ceased), nature_juridique | - |
| Revenue | ca_min, ca_max, resultat_net_min, resultat_net_max | Only companies that filed accounts have figures. |
| Flags | est_ess, est_association, est_entrepreneur_individuel, est_rge, est_qualiopi and others | - |
| Output size | minimal=true&include=siege,finances,dirigeants | Without it, every record is large. |
There is no creation-date filter: date_creation is an output field only, so "companies created last month" cannot be asked of this API.
What the records look like
- Identifiers:
siren(9 digits, the company),siege.siret(14 digits, an establishment). The EU VAT number is derived from the SIREN (tva). - Finances come as
{"2024": {"ca": ..., "resultat_net": ...}}, keyed by year: use the maximum key for the latest year. In our 20-company sample, 17 have a latest revenue figure. - Partial diffusion. When the owner (typically a sole trader) restricts diffusion, the API replaces address and similar fields by the literal string
[NON-DIFFUSIBLE]. In four pages of sole traders in the Rhône we counted 192 such strings. Fully non-diffusible companies are not served at all, and neither are companies whose trade-register registration was refused. - Commercial prospecting flag:
opposition_diffusion_commercialeis true when the business objected to being used for commercial prospecting. 14 of the 20 companies in our sample have it set, so large companies use it too. - Directors:
dirigeantsmixes legal entities (personne morale: SIREN and denomination) and natural persons (personne physique), whose entries carrynom,prenoms,date_de_naissanceandnationalite. - Freshness:
date_mise_a_jourwas within the day for the companies we checked; INSEE and trade-register fields have their own update dates (date_mise_a_jour_insee,date_mise_a_jour_rne). - This is a search API, not the full SIRENE base. The docs say it cannot give the complete SIRENE data; for the full stock files use the data.gouv.fr dataset (section 5).
2. DIY: companies to CSV in Python
This script (tested on 5 November 2026: 10,000 matches for two software NAF codes in Paris, 100 written) pages through results under the rate limit, retries on 429 and 5xx, leaves sole traders out and flattens the head-office address and the latest revenue. It needs pip install requests. Directors are deliberately not read.
import csv
import time
import requests
URL = "https://recherche-entreprises.api.gouv.fr/search"
# activite_principale takes EXACT NAF rev. 2 codes (e.g. 62.01Z). "62" or "62.0" is HTTP 400
# and the error lists the 732 valid codes. NAF 2025 codes are not accepted.
NAF = ["62.01Z", "62.02A"]
PARAMS = {
"activite_principale": ",".join(NAF),
"departement": "75", # matches companies with ANY establishment in Paris, not only head offices
"etat_administratif": "A", # active only
"est_entrepreneur_individuel": "false", # leave sole traders out: their business name is a person's name
"per_page": 25, # 1-25, above is HTTP 400
}
MAX_WINDOW = 10_000 # page * per_page must not exceed this, whatever total_results says
rows, page = [], 1
while page * PARAMS["per_page"] <= MAX_WINDOW and len(rows) < 100: # demo: 100 companies
for attempt in range(5):
r = requests.get(URL, params={**PARAMS, "page": page}, timeout=30)
if r.status_code in (429, 500, 502, 503, 504):
time.sleep(int(r.headers.get("Retry-After", 2 ** attempt)))
continue
r.raise_for_status() # 400 = JSON {"erreur": "..."}
break
data = r.json()
if page == 1:
print(data["total_results"], "matches (capped at 10000)")
for c in data["results"]:
s = c.get("siege") or {}
fin = (c.get("finances") or {})
last = max(fin) if fin else None # {"2024": {"ca": ..., "resultat_net": ...}}
rows.append({
"siren": c["siren"], "name": c["nom_complet"], "naf": s.get("activite_principale"),
"legal_form": c.get("nature_juridique"), "employees_band": c.get("tranche_effectif_salarie"),
"category": c.get("categorie_entreprise"), "created": c.get("date_creation"),
"hq_city": s.get("libelle_commune"), "hq_postcode": s.get("code_postal"),
"revenue": fin[last].get("ca") if last else None, "revenue_year": last,
"url": f"https://annuaire-entreprises.data.gouv.fr/entreprise/{c['siren']}",
})
if page >= data["total_pages"]:
break
page += 1
time.sleep(0.2) # stay far below 7 requests per second per IP
with open("companies_fr.csv", "w", newline="", encoding="utf-8") as f:
w = csv.DictWriter(f, fieldnames=rows[0].keys())
w.writeheader()
w.writerows(rows)
print(len(rows), "companies written")
3. When the Actor saves time
For a one-off list, the script is enough and free. The Apify Actor France Company Search (by Nexus Scrapers) wraps the same official API. It pays off when you would otherwise maintain that code:
- NAF prefixes and NAF 2025. You pass
62or62.0and the Actor expands it into the exact rev. 2 codes; NAF 2025 codes are mapped back to rev. 2 through INSEE's correspondence table. Both NAF versions are in the output, with official labels for NAF, legal form, size band, region and department. - A flat, stable record: head office as one object, latest and historical revenue, labels as a list, SIREN-based VAT number, source link, null for hidden values (
[NON-DIFFUSIBLE]is converted tonulland the record saysdiffusionStatus: partial). - Privacy defaults: natural-person directors are dropped in memory and never reach the dataset; legal-entity directors are kept. An
includeDirectorsoption exists, adds personal data and makes you responsible for it; it is never applied to partial-diffusion companies. There are inputs to exclude sole traders and companies that objected to commercial prospecting. - Lookups by SIREN or SIRET in bulk, input validation, retries and pacing (4 requests per second, below the limit).
- Scheduling and integrations through Apify: runs into Slack, e-mail, Google Sheets or a webhook; export as JSON, CSV or Excel; API and MCP access.
Pricing is pay per result; the Actor page shows the current price.
Limits: it inherits the API's 10,000-result window (split by department or NAF to go beyond), the establishment-level location filter, the lack of a creation-date filter and the absence of non-diffusible companies. It has no beneficial-owner data and no filed accounts documents. For a single list, use the script.
4. Real sample: 20 normalized records
These 20 records were produced on 5 November 2026 by running the Actor's own code locally on live API responses (no Apify platform involved): 12 software-programming companies (NAF 62.01Z) with an establishment in Paris and 50 to 249 employees, 4 restaurant companies (56.10A) with an establishment in the Rhône and 4 supermarket companies (47.11D) with an establishment in Occitanie, largest first. Because of the establishment-level location filter, several head offices are elsewhere, and the workforce band is that of the company, so a few show no employees at all. They are the first matches in that order, not hand-picked for quality.
No natural-person data. Sole traders were excluded with the Actor's own filter, natural-person directors are dropped by default (the only directors kept are legal entities), and there are no contacts. A scrub pass over all text fields found no e-mail address or phone number. The names are company names; the head-office address is the registered business address.
Download: sample.json (full records, UTF-8) and sample.csv (flattened, lists joined with | , opens in Excel). Free to use under the licence in section 5.
| SIREN | Name | NAF | Legal form | Size | Head office | Revenue |
|---|---|---|---|---|---|---|
| 387495799 | VISIATIV SOLUTIONS ENTREPRISE | 62.01Z | SAS | GE | CHARBONNIERES-LES-BAINS | 84,495,737 EUR (2024) |
| 851035329 | CHAPSVISION | 62.01Z | SAS | ETI | SURESNES | 156,671,000 EUR (2024) |
| 519037253 | TRUSTTEAM (TRUSTTEAM) | 62.01Z | SAS | PME | MAXEVILLE | 8,904,988 EUR (2022) |
| 823393764 | CLUB EMPLOYES | 62.01Z | SAS | PME | SAINTE-FOY-LES-LYON | 76,199,037 EUR (2025) |
| 439737222 | ORISHA PROPERTY MANAGEMENT (O… | 62.01Z | SAS | ETI | SAINT-DENIS | 33,767,618 EUR (2025) |
| 820334951 | LITTLE WORKER | 62.01Z | SAS | PME | BORDEAUX | 21,698,113 EUR (2021) |
| 487549693 | ALTRAN PROTOTYPES AUTOMOBILES | 62.01Z | SAS | GE | ISSY-LES-MOULINEAUX | 44,021,000 EUR (2025) |
| 518892211 | SILAE | 62.01Z | SAS | ETI | AIX-EN-PROVENCE | 56,508,017 EUR (2022) |
| 813754389 | UNITY TECHNOLOGIES SARL | 62.01Z | Société à responsabil… | PME | PARIS | 19,496,273 EUR (2025) |
| 817451313 | GALADRIM | 62.01Z | SAS | PME | PARIS | - |
| 400300190 | GLOBANT FRANCE (PENTALOG FRAN… | 62.01Z | SAS | ETI | PARIS | 66,074,854 EUR (2024) |
| 752946863 | LEARNINGSHELTER | 62.01Z | SA à conseil d'admini… | PME | PARIS | 16,398,933 EUR (2025) |
| 318906443 | BUFFALO GRILL | 56.10A | SAS | ETI | MONTROUGE | 305,303,715 EUR (2025) |
| 305836033 | SERARE | 56.10A | SAS | - | EVRY-COURCOURONNES | 189,805,347 EUR (2018) |
| 888796430 | NEW COURT | 56.10A | SAS | ETI | MONTROUGE | 119,852,026 EUR (2022) |
| 311160592 | SODEXO SPORTS ET LOISIRS | 56.10A | SAS | GE | GUYANCOURT | 196,083,975 EUR (2025) |
| 343262622 | LIDL (LIDL) | 47.11D | Société en nom collec… | GE | CHATENAY-MALABRY | - |
| 410409015 | AUCHAN SUPERMARCHE | 47.11D | SAS | GE | VILLENEUVE-D'ASCQ | 3,016,900,000 EUR (2024) |
| 493318067 | ALDI MARCHE TOULOUSE | 47.11D | Société à responsabil… | GE | SAINT-SULPICE-LA-POINTE | 726,383,284 EUR (2024) |
| 929781524 | A+SUPER | 47.11D | SAS | GE | LILLE | - |
One record in full. Note that the head office of this "Paris" company is in the Rhône, because the department filter matches any establishment:
{
"schemaVersion": "1.0",
"siren": "387495799",
"name": "VISIATIV SOLUTIONS ENTREPRISE",
"legalName": "VISIATIV SOLUTIONS ENTREPRISE",
"acronym": null,
"legalFormCode": "5710",
"legalForm": "SAS, société par actions simplifiée",
"nafCode": "62.01Z",
"nafLabel": "Programmation informatique",
"naf2025Code": "62.20H",
"naf2025Label": "Gestion d'installations informatiques et maintenance de systèmes et d'applications informatiques",
"activitySection": "J",
"activitySectionLabel": "Information et communication",
"creationDate": "1992-05-04",
"closureDate": null,
"status": "active",
"employeeBandCode": "22",
"employeeBand": "100 à 199 salariés",
"employeeBandYear": 2024,
"category": "GE",
"categoryYear": 2024,
"isEmployer": false,
"establishmentsCount": 48,
"openEstablishmentsCount": 15,
"headOffice": {
"siret": "38749579900067",
"address": "26 RUE BENOIT BENNIER 69260 CHARBONNIERES-LES-BAINS",
"postalCode": "69260",
"city": "CHARBONNIERES-LES-BAINS",
"communeCode": "69044",
"department": "69",
"region": "84",
"latitude": 45.776120571,
"longitude": 4.7489782507,
"departmentName": "Rhône",
"regionName": "Auvergne-Rhône-Alpes",
"tradeNames": null
},
"latestFinancialYear": 2024,
"latestRevenue": 84495737,
"latestNetIncome": 3817639,
"financials": [
{
"year": 2024,
"revenue": 84495737,
"netIncome": 3817639
}
],
"labels": [
"QUALIOPI",
"ORGANISME_FORMATION"
],
"isSoleTrader": false,
"isAssociation": false,
"isPublicService": null,
"collectiveAgreements": [
"1486"
],
"vatNumber": "FR27387495799",
"diffusionStatus": "full",
"commercialUseOpposition": true,
"corporateDirectors": [
{
"siren": "395008246",
"name": "VISIATIV",
"role": "Président de SAS"
}
],
"updatedAt": "2026-11-04T11:24:43",
"sourceUrl": "https://annuaire-entreprises.data.gouv.fr/entreprise/387495799",
"source": "recherche-entreprises.api.gouv.fr",
"scrapedAt": "2026-11-05T07:50:40+00:00"
}
5. Data licence and terms
The underlying register data is open data. The SIRENE dataset on data.gouv.fr (publisher: INSEE) is under the Licence Ouverte / Open Licence 2.0 (Etalab): free reuse, commercial included, if you credit the source and the date of the last update. The API's own page on api.gouv.fr says "Licence non renseignée", and its OpenAPI file declares MIT for the software, so the data licence is the one of the sources, not of the API. Credit "INSEE, base Sirene" and the Annuaire des Entreprises, and say when you downloaded the data.
Two obligations sit outside the licence. Diffusion restrictions: the API already hides what owners asked to hide, and you must not try to recover it from other fields. Personal data: a sole trader's name and the names and birth dates of directors are personal data under the GDPR even though they are public; reuse needs your own lawful basis and information duties. Businesses may also object to commercial prospecting (opposition_diffusion_commerciale); respect it when you build marketing lists. This is a summary, not legal advice.