Company lookup
GET /api/company/lookup returns the legal identity of a French company from a SIREN, a SIRET, a French VAT number, a company name or the name of the person who runs it, synchronously. Built to prefill a form.
Company lookup
GET /api/company/lookup turns what a user types into a checked company record, in a single synchronous call: legal name, legal form, NAF activity code, head office address, intra-community VAT number with its VIES status, main officer, and check-digit controls.
Typical use: a signup or invoicing form where the user types a SIREN, a SIRET, the start of a company name or their own name, and your code fills in every other field.
Works with API keys as well as session cookies.
Sources
| Data | Source |
|---|---|
| Identity, legal form, NAF, head office, establishment, sole proprietor | SIRENE register (INSEE), updated every day from INSEE's change feed (INSEE usually publishes changes one to two days late) |
Company officer (dirigeant) of a company |
Same register, fetched at query time; only on lookups by identifier and on searches by person |
VAT status (tva_statut) |
VIES (European Commission), queried at request time |
GET /api/company/lookup
| Query param | Type | Notes |
|---|---|---|
q |
string, required unless nom is given |
A SIREN (9 digits), a SIRET (14 digits), a French VAT number (FR + 11 digits) or a company name. Spaces, dots, dashes and underscores are ignored in identifiers: 995 260 130 works. |
nom |
string, optional | Instead of q: last name of a person, 2 to 120 characters. Returns the companies that person runs. See Search by person. |
prenom |
string, optional | With nom: given name of that person, up to 120 characters. |
naf |
string, optional | Activity filter for a name search or a search by person: one or several NAF codes separated by commas, e.g. 66.22Z. See Activity filter. |
naissance |
string, optional | With nom: the person's year and month of birth (YYYY-MM, e.g. 1975-04), or the year alone (YYYY). Used to tell namesakes apart. See Telling namesakes apart. |
limit |
int 1 to 10 | Default 5. Maximum number of candidates for a name search or a search by person. An identifier returns at most one company. |
How q is read:
FR+ 11 digits: VAT number. The 2-digit key must match the SIREN it contains, then the lookup runs on that SIREN.- 9 digits: SIREN. 14 digits: SIRET. Both must pass their check digit (see Controls).
- Any other all-digit input: rejected (
format_invalide). - Anything else: name search, 2 to 120 characters. Candidates are distinct companies (one per SIREN), best text match first.
curl -s "https://outsend.xyz/api/company/lookup?q=410409460" \
-H "Authorization: Bearer osk_..."
Response: 200 OK
Real response for SIREN 410409460:
{
"requete": "410409460",
"type_requete": "siren",
"nb_resultats": 1,
"resultats": [
{
"siren": "410409460",
"siret_siege": "41040946000756",
"raison_sociale": "AUCHAN HYPERMARCHE",
"sigle": null,
"forme_juridique": {
"code": "5710",
"libelle": "SAS, société par actions simplifiée"
},
"naf": {
"code": "47.11F",
"libelle": "Hypermarchés"
},
"date_creation": "1997-01-03",
"etat": "actif",
"adresse_siege": {
"rue": "200 RUE DE LA RECHERCHE",
"code_postal": "59491",
"ville": "VILLENEUVE-D'ASCQ",
"code_commune": "59009"
},
"etablissement": null,
"dirigeant": {
"type": "personne_morale",
"nom": "AUCHAN RETAIL FRANCE",
"prenoms": null,
"qualite": "Président de SAS"
},
"naissance_concorde": null,
"tva_intracom": "FR20410409460",
"tva_statut": "inconnu",
"tva_verifiee_le": null,
"controles": {
"siren_luhn": true,
"siret_siege_luhn": true
}
}
]
}
tva_statut is inconnu here because the French VIES service was saturated at the time of the call; see VAT status.
A lookup that matches nothing returns 200 with nb_resultats: 0 and an empty resultats list.
Search by person
Pass nom and prenom instead of q to get the companies a person runs: the sole proprietorships registered in that name, and the companies where that person is listed as an officer. The response has the same shape as a name search, with type_requete: "personne", and dirigeant is that person in every result.
curl -s "https://outsend.xyz/api/company/lookup?nom=arnault&prenom=bernard&naf=64.20Z&limit=1" \
-H "Authorization: Bearer osk_..."
Real response, on 2026-10-09:
{
"requete": "bernard arnault",
"type_requete": "personne",
"nb_resultats": 1,
"resultats": [
{
"siren": "582110987",
"siret_siege": "58211098700010",
"raison_sociale": "CHRISTIAN DIOR",
"sigle": null,
"forme_juridique": {
"code": "5800",
"libelle": "Société (autre forme)"
},
"naf": {
"code": "64.20Z",
"libelle": "Activités des sociétés holding"
},
"date_creation": "1958-01-01",
"etat": "actif",
"adresse_siege": {
"rue": "30 AVENUE MONTAIGNE",
"code_postal": "75008",
"ville": "PARIS",
"code_commune": "75108"
},
"etablissement": null,
"dirigeant": {
"type": "personne_physique",
"nom": "ARNAULT",
"prenoms": "BERNARD",
"qualite": "Président du conseil d’administration"
},
"naissance_concorde": null,
"tva_intracom": "FR69582110987",
"tva_statut": "inconnu",
"tva_verifiee_le": null,
"controles": {
"siren_luhn": true,
"siret_siege_luhn": true
}
}
]
}
How the person is matched:
- Case, accents and hyphens are ignored. Every word of
nommust appear in the person's last name (birth name or usage name), and every word ofprenomamong their given names: someone registered as "Jean Louis" is found withprenom=jean. Results where the last name and the first given name match exactly come first. prenomis optional, but a last name alone matches far more people thanlimitcan return. Send both.- Sole proprietors and companies alternate in the list, so neither kind is pushed out by
limit. qandnomcannot be sent together (format_invalide).
Limits:
- Only active companies are returned.
- Two people with the same name come back together. See Telling namesakes apart.
- People whose data the register does not disclose are not returned.
- Company officers are fetched at query time, with a 2-second limit. When they could not be fetched, the answer contains the sole proprietors only and nothing in it says so: that answer is not cached, so sending the request again returns the full list.
dirigeant.prenomslists every given name the register holds for an officer of a company, and only the first one for a sole proprietor.
Telling namesakes apart
If you know when the person was born, send naissance with nom and prenom: year and month (naissance=1949-03), or the year alone (naissance=1949). Every result then carries naissance_concorde:
naissance_concorde |
Meaning |
|---|---|
true |
The register knows this officer's birth and it matches yours |
false |
The register knows it and it differs |
null |
Cannot be told: the register gives no birth for this person, it gives the year only while you sent a month of that same year, or naissance was not sent |
trueresults come first, thennull, thenfalse.limitapplies after this ranking.falseresults are not removed: a date in the register can be wrong. Discarding them is your call.- The comparison is made to the month when you send
YYYY-MM, to the year withYYYY. The register never knows the day. - The answer never contains the date of birth, only this field.
- With
naissance, the companies of a namesake born in that period are looked up across the whole register, not only among the first results for the name: the right person comes up even when the name is very common. - When a company has two officers with the same name,
dirigeantis the one whose birth matches. - The birth of a company officer is almost always known. That of a sole proprietor less often: out of 12 sole proprietors in a search run on 2026-10-09, 7 had a known birth. Expect
nullfor them. - Without
nom,naissanceis checked then ignored. A malformed value is rejected withnaissance_invalide: onlyYYYY-MM(month 01 to 12) andYYYYare accepted, from 1900 to the current year.
Measured on 2026-10-09: nom=arnault&prenom=bernard returns a sole proprietorship in Charente-Maritime first; with naissance=1949-03, the five results are Paris companies marked true, among them CHRISTIAN DIOR and LVMH; with naissance=1961-01, four companies in Valence marked true, then the sole proprietorship marked false.
When naissance_concorde is null everywhere, or when you do not have the birth, each result carries enough to choose by eye without another call: raison_sociale, forme_juridique, naf, date_creation, adresse_siege (street, postcode, city), siren and dirigeant.qualite. Narrow the list with naf first.
Activity filter
naf keeps only the companies whose main activity (the naf.code field of the response) is one of the codes you send. It applies to name searches and searches by person, before limit: a company in the right trade is not pushed out by better-ranked namesakes in other trades.
- One code or several separated by commas, 20 at most:
naf=66.22Z,66.21Z. 66.22Z,6622Zand66.22zare the same code. Anything else is rejected withnaf_invalide.- On a SIREN, a SIRET or a VAT number,
nafis ignored: the company is returned whatever its activity.
Measured on 2026-10-09: q=dior&limit=3 returns DIOR, DIOR SOUSSI and DIOR MONTRES (activities 68.20B, 68.20B, 46.18Z); q=dior&naf=64.20Z&limit=3 returns CHRISTIAN DIOR first.
Fields
| Field | Notes |
|---|---|
siren |
9 digits |
siret_siege |
SIRET of the head office, or null if none is known |
raison_sociale |
Registered name. For a sole proprietor: first name and last name (usage name first when there is one) |
sigle |
Acronym, or null |
forme_juridique |
INSEE legal category: code (e.g. 5710) and libelle |
naf |
Main activity: NAF/APE code and libelle. libelle is null for codes from older nomenclatures |
date_creation |
YYYY-MM-DD |
etat |
actif or ferme (company ceased) |
adresse_siege |
rue, code_postal, ville, code_commune (INSEE municipality code), as the register writes them. null if unknown |
etablissement |
Only when q is a SIRET: the requested establishment (siret, est_siege, rue, code_postal, ville). null otherwise, or when that establishment cannot be found (the company itself is still returned) |
dirigeant |
type (personne_physique or personne_morale), nom (last name, or company name for a legal person), prenoms, qualite. See below |
naissance_concorde |
true, false or null. Set only on a search by person with naissance, null in every other case. See Telling namesakes apart |
tva_intracom |
Intra-community VAT number computed from the SIREN |
tva_statut |
valide, non_attribue or inconnu. See VAT status |
tva_verifiee_le |
ISO timestamp of the VIES answer, null when the status is inconnu |
controles |
Check-digit results. See Controls |
dirigeant is filled only:
- for a sole proprietor (
personne_physique,qualite: "Entrepreneur individuel"), whatever the query type; - for a company, when the query is a SIREN, a SIRET or a VAT number: the first officer listed in the register;
- for a company, on a search by person: the officer who matches the requested name.
On a name search, dirigeant is null for companies. It can also be null when the register lists no officer, or when that information could not be fetched in time.
VAT status
tva_intracom is always computed (FR + key + SIREN). The computation says nothing about whether the number was actually issued, so each number is checked against VIES:
tva_statut |
Meaning |
|---|---|
valide |
VIES confirms the number is active. This is the only case where you may treat the VAT number as valid. |
non_attribue |
VIES answers that the number is not valid: not issued, or no longer active (e.g. a business not registered for VAT). |
inconnu |
VIES did not answer in time (the French service is frequently saturated). The check goes on in the background: sending the same request again a few seconds later usually returns the final status. Never treat inconnu as valid. |
Within the request, VIES is given 0.8 seconds at most. When it has not answered by then, the background check keeps retrying for up to 20 seconds. Final answers are kept 24 h (valide) and 6 h (non_attribue); inconnu is never kept.
On a name search, VIES is not called within the request: each candidate's status comes from that cache, so it is often inconnu, and a background check starts for every candidate not in the cache. Recommended flow: search by name, let the user pick a candidate, then call again with that candidate's SIREN to get the checked status.
Controls
| Field | Check |
|---|---|
siren_luhn |
Luhn check digit of the SIREN |
siret_siege_luhn |
Check digit of the head office SIRET: Luhn, or the La Poste rule (SIREN 356000000, where the sum of the 14 digits is a multiple of 5). null when no head office SIRET is known |
The same checks are applied to q before any lookup: an identifier that fails them is rejected with 400.
Caching
Register data for a given query is cached 10 minutes. The VAT status follows its own cache (above), so a result whose status was inconnu is re-checked on the next call.
Errors
400 Bad Request
{
"detail": {
"code": "siret_invalide",
"message": "Ce SIRET n'est pas valide : sa clé de contrôle est incorrecte. Vérifiez les 14 chiffres.",
"suggestion": {
"siret_siege": "41040946000756",
"raison_sociale": "AUCHAN HYPERMARCHE"
}
}
}
That is the real answer to q=41040946000750 (last digit mistyped). Branch on detail.code, which is stable; detail.message is a readable French sentence you can show to the user.
code |
When |
|---|---|
siren_invalide |
9 digits whose check digit is wrong |
siret_invalide |
14 digits whose check digit is wrong. When the first 9 digits are a valid, known SIREN, suggestion gives that company's head office SIRET and name |
tva_invalide |
FR followed by something other than 11 digits, or a key that does not match the SIREN |
format_invalide |
All digits but neither 9 nor 14 of them, a name longer than 120 characters, or q and nom sent together |
requete_trop_courte |
Fewer than 2 characters, or prenom sent without nom |
naf_invalide |
naf contains something that is not a NAF code, or more than 20 codes |
naissance_invalide |
naissance is neither YYYY-MM nor YYYY, or names an impossible month or year |
401 / 403
401 without valid credentials. See Authentication.
429 Too Many Requests
Limits are per account (all keys and the browser session together):
- 60 requests per minute;
- 5,000 requests per day.
Every call counts, including rejected ones. The response carries a Retry-After header (seconds):
{ "detail": "Trop de requêtes. Réessayer dans 43s." }
Response time
For a SIREN, a SIRET or a VAT number, the VAT check waits for VIES for 0.8 s at most, then reports the status as unknown. The first lookup of a company can take up to about 2 s, because its officer is fetched at that point; the same company is then served from cache. A name search does not wait for VIES. Measured on 15 names through the public API, very common words included, a name search answered in 0.09 to 0.44 s end to end on first call, and in 0.04 to 0.11 s when repeated. With naf, the same search took 0.06 to 0.26 s on 3 queries; on a very common single word it stops after about 0.7 s and returns what it has found by then.
A search by person waits for the company officers: 1.1 to 1.6 s on first call, measured on 7 searches inside the application on 2026-10-09, then about 0.01 s for 10 minutes when repeated. With naissance, the first call took 1.1 to 1.7 s over 5 searches the same day. It never waits more than about 2 s, and does not wait for VIES.
What's next
- Authentication: create an API key
- SIRENE module: bulk extraction from the same register