Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Recherche Entreprises Bundle Laravel Package

philippe2463/recherche-entreprises-bundle

A Symfony bundle that integrates the French Recherche d'entreprises API, letting you search companies by name, SIREN/SIRET, or location and retrieve structured business data directly in your PHP applications.

View on GitHub
Deep Wiki
Context7

Getting Started

This is a Symfony bundle, not a Laravel package — so the first step for a Laravel developer is deciding whether the value you want is the bundle or the underlying API. The bundle itself only wires a service around the public Recherche d'entreprises API (https://recherche-entreprises.api.gouv.fr/search). If you're on Laravel, skip the bundle and hit the API directly through Http::get() — you get 90% of the value with 10 lines of code; if you're on Symfony, composer require philippe2463/recherche-entreprises-bundle and register the bundle.

Where to look first:

  1. The bundle's service class (whatever wraps the HTTP client) — it exposes the search/lookup methods you'll actually call.
  2. Its Configuration.php / services.yaml — the configurable API client settings (base URI, timeout, headers) and whether the API client is meant to be decorated.
  3. The API's own docs (recherche-entreprises.api.gouv.fr) — the bundle is a thin wrapper; the query parameters are the real surface.

First use case: company autocomplete / onboarding lookup. User types a company name, you show matches with SIREN, SIRET, address, and etat_administratif; selecting one persists the SIREN locally as the canonical key. Second use case: exact lookup by SIREN/SIRET for enrichment (filling in legal name, address, NAF code, headcount band from a SIREN the user already entered).

If you're on Laravel, write the equivalent as a small service class (App\Services\CompanyLookup) using Http::withHeaders([...])->timeout(...) and the same methods. Don't try to shoehorn a Symfony bundle into a Laravel app.

Implementation Patterns

Autocomplete search. Call the search endpoint with q (name), page, per_page and the departement/code_postal filters when scoped. Debounce on the frontend, and cache per normalized query string (e.g. Hash::make($q.'|'.$page) → 5–15 min TTL) — the data is public and slow-changing, so this kills most of your API volume.

Exact lookup. Branch on identifier before calling: 9-digit input → query by siren, 14-digit → query by siret. Never send a SIRET to the SIREN parameter; validate with preg_match('/^\d{9}(\d{5})?$/', $input) before dispatch.

Persist the SIREN, not the API payload. The API returns siege and matching_etablissements; store the canonical siren on your Company/Organization model plus a raw JSON column (or a company_snapshots table) so you can enrich later without re-fetching. Treat the API as the system of record for identity, your DB as the system of record for the relationship.

Adapter boundary. Wrap the bundle/service behind your own interface (CompanyLookup::search(), ::bySiren(), ::bySiret()) even in Symfony. At 0.x you want to swap the implementation (or vendor a fork) without touching controllers. The interface should return your own DTO — not the bundle's response object — so upstream shape changes are a one-file edit.

Filtering on read, not on write. Don't filter out closed/radiated companies at persist time — you may legitimately need to reference one. Filter in the presentation layer using etat_administratif === 'A' (active).

Multi-tenant onboarding. When a new customer signs up "as a company," the flow is: search by name → user picks → fetch by SIREN → confirm legal name + address → persist. Run the confirm-fetch on the backend even though the client already has the payload, so an attacker can't submit an arbitrary SIREN with a spoofed name.

Queued enrichment. For bulk backfills (importing a CSV of SIRENs), push one job per SIREN onto a queue with a rate limiter, not a synchronous loop. The public API is rate-limited; a RateLimiter or Bus::batch()->withDelay() keeps you polite and avoids 429s.

Gotchas and Tips

Framework mismatch is the headline. This is a Symfony bundle; installing it in a Laravel app will not work and will not be supported. If you're on Laravel, re-implement the thin client yourself — it's a day of work — or fork the bundle and strip the Symfony DI. Do not add symfony/* to a Laravel project to make this run.

v0.1.0 means no stability contract. Semver permits breaking changes in minor bumps. Pin exactly ("philippe2463/recherche-entreprises-bundle": "0.1.0") and commit the lockfile. There are no release notes and no stated test suite; verify behavior with a smoke test that asserts a known SIREN returns the expected legal name, so an auto-discovery failure after a framework upgrade is caught rather than silently no-op'ing.

Validate SIREN/SIRET before dispatch. SIREN is 9 digits, SIRET is 14. The API will happily return empty results for malformed input; you'll spend an hour debugging "why no match" before realizing the Luhn check or digit count is wrong. Run the Luhn checksum on SIREN too — it catches typos that would otherwise silently resolve to a different company.

etat_administratif matters. The API returns both active (A) and closed (C) companies. Autocomplete should default to active; lookups for historic invoices may need both. Make this an explicit parameter, not an implicit assumption.

Result shape is a wrapper. Responses look like {results: [...], total_results, page, per_page, total_pages}. If you're paginating, respect total_pages from the response rather than computing from total_results yourself — the per_page cap is server-controlled and changes.

The siege vs. etablissements split trips people up. A siren can have many etablissements; siege is the head office. For "where is this company" you almost always want siege.adresse, not the first matching establishment. For "does this company have a branch in Lyon" you want matching_etablissements.

Debugging HTTP in Symfony. Use the profiler's HTTP Client panel (requires framework.http_client.profiler: true) to see the actual outgoing request and response — invaluable when the API returns an unexpected empty set. In Laravel, Http::fake() in tests and Http::dd() in dev.

Cache aggressively, but not forever. Public company data changes on the order of weeks (headcount bands, addresses, closures). A 15-minute TTL on search and a 24-hour TTL on SIREN lookups is a reasonable starting point. Key the cache by the full normalized query, and namespace it so you can bust it when you change DTOs.

Rate limits are the operational risk. The API is free and public but throttled. Log the response status and any Retry-After header, and back off on 429 with jitter. A queue worker stuck in a tight retry loop against a government API is a bad look and can get your IP throttled harder.

Exit cost is low — keep it that way. Because the wrapper is thin, the fallback is direct Http calls in your own service. Keep the adapter interface, keep the DTOs yours, and you can drop the package in an afternoon if it's abandoned or a breaking 0.x release lands.

Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
abbasudo/artisan-route
mirvan/ippanel
ignibyte/aic-framework
glavweb/data-schema-bundle
glavweb/datagrid-bundle
tacticmedia/scim-server
uni-method/frame
neika-ai/sdk
adachsoft/php-code-style
pharaonic/laravel-notification-dependencies
beautinow/translug
dev-brainiac/bot-cloaked
octoberrain/html
octoberrain/extension
octoberrain/exception
octoberrain/contracts
adachsoft/api-version-bundle
cgv/localized-resource
noith/settings
kda/laravel-package