Company lookup
GET /api/company/lookup returns the legal identity of a French company from a SIREN, a SIRET, a French VAT number or a name, 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 or the start of a company 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 |
VAT status (tva_statut) |
VIES (European Commission), queried at request time |
GET /api/company/lookup
| Query param | Type | Notes |
|---|---|---|
q |
string, required | 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. |
limit |
int 1 to 10 | Default 5. Maximum number of candidates for a name search. 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"
},
"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.
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 |
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.
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, or a name longer than 120 characters |
requete_trop_courte |
Fewer than 2 characters |
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.
What's next
- Authentication: create an API key
- SIRENE module: bulk extraction from the same register