# Changelog of Company Register Search: France SIREN/SIRET + Global LEI (`humble-echidna/company-registers`) Actor

- **URL**: https://apify.com/humble-echidna/company-registers/changelog.md
- **Full Actor documentation**: https://apify.com/humble-echidna/company-registers.md

## Changelog

Versions follow MAJOR.MINOR.PATCH (`src/version.py`); Apify shows MAJOR.MINOR from `.actor/actor.json`.
Every run logs its version and records it in the `RUN_STATS` key-value record.

### 1.1.0 (2026-09-26)

- New `mode` input. `search` (the default, unchanged) is everything 1.0 did. `newCompanies` returns the companies
  newly registered in France from BODACC A, DILA's daily XML files
  (`https://echanges.dila.gouv.fr/OPENDATA/BODACC/FluxAnneeCourante/RCS-A_BXA<year><issue>.taz`): place filters
  (`departments`, the new `regions`, `postalCodes`) applied locally, and optional NAF filters (`activityCodes`,
  `activitySections`) through one API Recherche d'entreprises lookup per company in the area. New inputs `sinceDays`
  (1-31, default 3), `onlyNew` (default true) and `maxNafLookups` (1-1,000, default 300). The default input is
  unchanged.
- Only new: one record per filter combination in the named store `company-registers-new-companies` (key
  `new-companies-<hash>`), holding SIRENs, dates and BODACC issue numbers only. A company is remembered once it's in
  the dataset. Later runs read only the issues after the last one read (at most 31 days back); a failed download
  isn't skipped over, so the next run reads it.
- A NAF filter needs a place filter. Companies INSEE hasn't classified yet (`00.00Z`), not yet in the register, whose
  lookup failed, or cut by the lookup cap, max results or max cost are held uncharged and retried on later runs for 7
  days after publication (`RUN_STATS.held` by reason).
- Companies only, by structure: notices with a `personnePhysique` (sole traders, two thirds of registrations) are
  dropped whole; `administration` (managers), `precedentProprietairePP/PM`, `precedentExploitantPP/PM`, `descriptif`
  and `origineFonds` are emptied as the parser closes them, so no code reads them. Only "Immatriculation d'une
  personne morale" creation notices (`acte/creation`, typeAnnonce `annonce`) are kept: transfers, GAEC
  transformations and corrections are left out. Tests feed notices naming people and check the names reach neither
  the dataset, the key-value stores nor the log.
- BODACC records: `register` `bodacc`, a new top-level `bodacc` block (announcement reference and number, issue,
  publication, registration and activity-start dates, category, `withoutActivity`, the activity as published, `naf`
  when looked up, acronym, trade name, capital, département, court), and the licence credit DILA asks for in
  `attribution`: `source` "bodacc.fr/DILA", `fileUrl`, `fileName`, `fileDate`. Those three are `null` on search
  records, and `bodacc` is `null` on them: new keys, nothing removed. A new "New companies" dataset view.
- `regions` (the 18 regions, as their départements) also works in search mode.
- The directory listing takes ~48 s to answer, so issues are found by number with HEAD requests (~0.4 s each), their
  Last-Modified date deciding the window; downloads are streamed to a temporary file (64 MB cap) and parsed with
  defusedxml, DTDs refused.

Source checked before building (2026-09-25/26; details in `notes/COMPANY-REGISTERS-BODACC-2026-09-25.md`):

- Published for machines: the data.gouv.fr dataset "BODACC" (`https://www.data.gouv.fr/datasets/bodacc`, licence
  `fr-lo`): "L'accès aux données est libre via les protocoles HTTPS : https://echanges.dila.gouv.fr/OPENDATA/", linking
  the "flux année courante" folder.
- Licence: DILA's data sheet (`https://echanges.dila.gouv.fr/OPENDATA/BODACC/DILA_BODACC_Presentation_20260327.pdf`,
  p. 2, "Conditions de réutilisation"): "Les données sont réutilisables gratuitement sous licence ouverte v2.0", crediting
  "la paternité des données (bodacc.fr/DILA)", "l'url d'accès longue de téléchargement" and "le nom du fichier
  téléchargé ainsi que la date du fichier" (hence the `attribution` fields). bodacc.fr legal notice: "Sauf mention
  contraire, tous les contenus de ce site sont sous licence etalab-2.0". bodacc.fr's CGU cover the site and e-mail
  alerts and have no clause on automated access or reuse. DILA's personal-data notice
  (`https://echanges.dila.gouv.fr/OPENDATA/AVERTISSEMENT-Donnees_a_caractere_personnel.pdf`) reminds reusers that
  data-protection law applies (hence companies only).
- robots.txt: `https://echanges.dila.gouv.fr/robots.txt` answers 404, so every path is allowed (RFC 9309), re-checked
  through `mms_common` on 2026-09-26 before building. The BODACC API (Opendatasoft, bodacc.fr and
  bodacc-datadila.opendatasoft.com) was not used: its robots.txt disallows `/api/` for every bot except Googlebot.

### 1.0.1 (2026-09-25)

- Input field descriptions rewritten for AI agents (Apify's MCP server shows agents only the description, not the
  form): each now states its default, its allowed range, the value of each option and how it combines with other
  fields. No change to field names, types, defaults or behaviour.
- `searchTerms` and `identifiers` say that a left-out `searchTerms` takes its default (`airbus`), so an identifier
  lookup passes `"searchTerms": []`; the README's MCP answer says the same.

### 1.0.0 (unreleased)

First release.

- Company lookup and search in two official, keyless registers: France's SIREN/SIRET register through the API
  Recherche d'entreprises (`https://recherche-entreprises.api.gouv.fr/search`, DINUM; INSEE Sirene, INPI RNE) and the
  Global LEI Index through the GLEIF API (`https://api.gleif.org/api/v1`). No API key, email address or other identity
  of anyone is sent; only the honest User-Agent.
- Inputs: company names (searched in every selected register, best match first), and SIREN, SIRET, French VAT
  numbers and LEIs in any common spelling or as Annuaire des Entreprises / GLEIF links, with check digits verified
  before any request. A search line that is a number is looked up as one. Filters alone run one search.
- Filters: status (both registers); France: NAF/APE activity codes, NAF sections, departments, postal codes, INSEE
  legal forms, size category, employee ranges, minimum/maximum revenue; LEI: countries, entity categories, LEI
  registration status. France and LEI filters can't be mixed (each register can only apply its own).
- One schema for both registers: common top-level fields plus `france` / `lei` blocks. French companies get their
  LEI (batched lookups by SIREN in both the Sirene and RCS spellings, 50 per request); LEI records get their SIREN
  from their French registration or OpenCorporates id. INSEE labels for activity, legal form and employee range codes
  (from the Annuaire des Entreprises' search-api label files, MIT, commit b85b033, 2026-08-25); LEI legal form names
  from GLEIF's ELF code list, fetched once per code per run.
- Every record carries its source, licence and last update date (`attribution`), as Licence Ouverte 2.0 asks.
- Companies only: directors are never requested (the French `include` list leaves `dirigeants` out); sole traders
  (INSEE legal form 1000) and groupings of named people (2110, 2210, 2310, 2385) are asked to be left out of searches
  and dropped client-side too, because a lookup by number returns them anyway; LEI sole proprietors are filtered out
  of every search and dropped client-side. Counted as `peopleLeftOut` in `RUN_STATS`.
- Paced below each published limit: France one request every 0.5 s (limit 7/s per IP, 30/s per network), the LEI
  index one every 1.05 s (limit 60/min). `Retry-After` honoured; a DNS failure on either fixed API host is retried
  twice.
- A company found by several inputs is returned and charged once (per register).
- Charged per company returned, through Apify's standard `apify-default-dataset-item` event.
- "Max results per run" input, and the maximum cost per run is honoured: once either is covered, inputs still
  being fetched are cancelled and the rest are skipped (listed as `queriesSkipped` in `RUN_STATS`).
- Failure isolation: a bad line, an unknown number or a failing search only affects itself; one register failing
  never hides the other's results (`registerErrors`); one company that can't be built doesn't affect the rest of its
  input; a failed LEI cross-link still returns the companies (`crossLinkFailed`).

Sources checked before building (2026-09-25):

- France, API for machines: the API's own documentation (`https://recherche-entreprises.api.gouv.fr/openapi.json`,
  shown at /docs) and its data.gouv.fr listing (`https://www.data.gouv.fr/dataservices/api-recherche-dentreprises`,
  "Conditions d'accès: Accès Ouvert"): "L'API étant totalement ouverte d'accès"; "L'API accepte au maximum 7 requêtes
  par seconde par adresse IP. Une limite de 30 requêtes par seconde par ASN est aussi en place. Il est donc probable
  de faire face à cette limite sur les cloud publics"; "Lorsque la limite est dépassée, le serveur renvoie une réponse
  HTTP 429 ... L'en-tête Retry-After indique le délai à respecter"; "Il est recommandé d'inclure un en-tête User-Agent
  explicite et descriptif". robots.txt: 404 (allow all).
- France, licence: the API's data is the data.gouv.fr dataset "Données des entreprises utilisées dans l'Annuaire des
  Entreprises" (licence `lov2`, read through the data.gouv.fr API), and the Annuaire's sources page (site repository,
  `src/routes/_header-default/donnees.sources.tsx`) says "Toutes les données accessibles sur le site proviennent d'un
  jeu de données librement téléchargeable sur data.gouv.fr". Licence Ouverte 2.0 text
  (`https://www.data.gouv.fr/pages/legal/licences/etalab-2.0`, re-read in full 2026-09-25): "Le « Concédant »
  concède au « Réutilisateur » un droit non exclusif et gratuit de libre « Réutilisation » de l'« Information » objet
  de la présente licence, à des fins commerciales ou non, dans le monde entier et pour une durée illimitée"; the
  reuser may "la diffuser, la redistribuer, la publier et la transmettre, de l'exploiter à titre commercial ... ou en
  l'incluant dans votre propre produit ou application. Sous réserve de : mentionner la paternité de l'«Information» :
  sa source (a minima le nom du « Concédant ») et la date de la dernière mise à jour de l'« Information » réutilisée"
  (hence `attribution`); "Cette mention de paternité ne doit ni conférer un caractère officiel à la « Réutilisation »
  ... ni suggérer une quelconque reconnaissance ou caution par le « Concédant »"; "La « Réutilisation » ne doit pas
  induire en erreur des tiers quant au contenu de l'« Information », sa source et sa date de mise à jour"; personal
  data "peut être librement réutilisée ... à condition de respecter le cadre légal relatif à la protection des
  données à caractère personnel" (hence companies only). data.gouv.fr's own terms (`/pages/legal/cgu`) put no
  condition on API users. The Annuaire's `/cgu` and `/donnees/api` pages sit behind a bot challenge (Incapsula) and
  couldn't be read directly; the site's source (github.com/annuaire-entreprises-data-gouv-fr/site) has no terms
  page, only `mentions-legales` (publisher: DINUM).
- Global LEI Index, API for machines: GLEIF API documentation
  (`https://documenter.getpostman.com/view/7679680/SVYrrxuU`): "There is no charge for the use of GLEIF's LEI data.
  GLEIF does not enter into individual contractual relationships with specific users of the LEI data. Rate limiting
  is currently set at 60 requests, per minute, per user, for all users." api.gleif.org/robots.txt: `Disallow:` empty
  (allow all).
- Global LEI Index, terms (`https://www.gleif.org/en/meta/lei-data-terms-of-use`): "The Access Service on the website
  http(s)://www.gleif.org is provided for free. The data available through the Access Service are provided under the
  CC0 licence"; users must access the data "only by way of using the Access Service" (the API is part of it: "Any
  such access might use file downloads, access via Web Interfaces/APIs"), and must refrain "from creating, in
  whatever way, the impression that, data and/or services, except the original LEI and LE-RD downloaded by you
  through the Access Service, are provided or supported or authorized or granted or otherwise associated by or with
  GLEIF" (hence the README's "not affiliated" line and no GLEIF logo or trademark use beyond naming the source).
  GLEIF's separate "AI Terms of Use" cover its chatbot only.
- Norway (Brønnøysund) was dropped before building: its robots.txt never answers, which our policy (RFC 9309:
  unreachable = disallow all) treats as a disallow.
