yoanbernabeu/recherche-entreprises-bundle
Symfony bundle for searching French companies through the official Recherche d'entreprises API. Query by name, SIREN, SIRET, or address and get structured results with legal form, activity, and location details, all wrapped in a simple, injectable PHP service.
This package wraps the French government's public Recherche d'entreprises API (recherche-entreprises.api.gouv.fr) — free, no API key, covers SIREN/SIRET lookup, full-text search, and now officer (dirigeants) data as of v0.1.1.
Install and first call:
composer require yoanbernabeu/recherche-entreprises-bundle:^0.1.1
Read the README first, then src/ — at v0.1.x the service surface is small (search + company lookup), so the README examples plus the upstream API docs at recherche-entreprises.api.gouv.fr/docs are the fastest path to understanding what fields come back.
Important integration note: despite being framed as a Laravel package, this is a Symfony bundle (hence the name). If you are on Laravel, do not assume php artisan vendor:publish works — check whether a Laravel service provider is shipped. If not, the pragmatic first use case is to call the API directly with Laravel's HTTP client and treat the bundle as reference documentation:
$results = Http::baseUrl('https://recherche-entreprises.api.gouv.fr')
->get('/search', ['q' => 'Carrefour', 'page' => 1, 'per_page' => 10])
->throw()
->json('results');
First use case to validate: look up a known company by SIREN and confirm you can read isAssociation (corrected in v0.1.1) and dirigeants (added in v0.1.1).
Search by name, then hydrate by SIREN. Search results are lightweight and paginated; once a user selects a company, fetch by SIREN/SIRET to get the full record including officers. Don't assume the search payload contains everything.
// Search
$search = $client->search(['q' => $request->input('q'), 'per_page' => 10]);
// Hydrate
$company = $client->findBySiren('652014051');
Use dirigeants for KYC / onboarding flows. The v0.1.1 addition is the headline feature — officer names, roles, and (where available) birth data let you build beneficial-owner checks, contract counterparty verification, or CRM enrichment without a paid data provider.
Wrap it behind your own service + repository. Keep the bundle's client out of controllers. Bind an interface in a service provider so you can swap in a cached or fake implementation:
$this->app->bind(CompanyLookup::class, ApiCompanyLookup::class);
Cache aggressively — the data changes slowly. A SIREN record is effectively static for days. Cache by SIREN with a TTL of 24h–7d, and cache search queries for minutes at most (result ordering shifts). Use Cache::remember("insee:{$siren}", ...).
Guard association logic with an explicit test. Because isAssociation was reported as erroneous before v0.1.1, add a regression test asserting both a known association and a known non-association return the expected boolean.
Fake the HTTP layer in tests. Use Http::fake() with captured fixtures from real API responses so you don't hit the public endpoint in CI.
^0.1.1 at minimum. The isAssociation fix and dirigeants are both in this release. On 0.1.0 you get wrong association flags and no officer data — a silent correctness bug if you're already using the package in production.dirigeants. Handle null/[] explicitly — do not assume officers exist for every SIREN. Same applies to some isAssociation edge cases.per_page (commonly 25). Requesting more silently truncates — never build UI assuming unbounded page size, and always check total_pages/total_results.results array means "no match" and is a UX state, not an error. Wrap calls with ->throw() only inside a try/catch that distinguishes these.nature_juridique codes when the outcome is legally load-bearing — belt and braces.null at your DTO boundary rather than an obvious error.How can I help you explore Laravel packages today?