cieplik206 / laravel-bir-regon
Laravel client for the Polish GUS BIR/REGON API
Requires
- php: ^8.4
- ext-curl: *
- ext-dom: *
- ext-libxml: *
- illuminate/cache: ^13.0
- illuminate/contracts: ^13.0
- illuminate/support: ^13.0
- spatie/laravel-data: ^4.14
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.0
- orchestra/testbench: ^11.0
- pestphp/pest: ^5.0
- pestphp/pest-plugin-laravel: ^5.0
- pestphp/pest-plugin-phpstan: ^5.0
This package is auto-updated.
Last update: 2026-08-24 15:25:49 UTC
README
A fluent Laravel client for the Polish GUS BIR/REGON SOAP API.
Use a Laravel facade or dependency injection to search businesses by NIP,
REGON, or KRS, retrieve full and bulk reports, and inspect the current GUS
service status. Search items and report payloads are returned as typed
spatie/laravel-data objects.
use cieplik206\BirRegon\Facades\BirRegon; $companies = BirRegon::forNip('1234567890')->get(); foreach ($companies as $company) { $company->name; $company->regon; }
Features
- Fluent plural and exact-one searches by NIP, REGON, and KRS without silently discarding additional GUS silo results
- Batch searches for up to 20 identifiers
- Native bounded cURL transport with SOAP 1.2, WS-Addressing, TLS 1.2 or newer, and strict timeout and response-size limits for the official GUS BIR 1.2 API
- Optional explicit HTTP or HTTPS proxy routing with CONNECT tunneling and verified TLS
- All 17 full report types, including BIR121, and all 6 bulk report types
- Separate production and sandbox clients with reusable sessions and HTTP connections
- Strict response enums and normalized full-report DTOs, with the original GUS rows retained
- Cache-backed enforcement of the official GUS request limits
- Identifier- and credential-safe translation of GUS and transport exceptions
- Credential-free serialization tombstones for clients and request builders
- Laravel auto-discovery, facade, and container bindings
- Isolated tests plus an opt-in live sandbox suite
Requirements
- PHP 8.4 or newer
- Laravel 13
- PHP cURL, DOM, and libxml extensions
The test matrix covers Laravel 13 on PHP 8.4 and 8.5 with Pest 5 and
pest-plugin-phpstan. PHP 8.4 is verified against both the lowest and highest
resolvable test toolchains, and a separate runtime check resolves the package
against PHP 8.4.0 and Illuminate 13.0. Applications that still require PHP 8.3
or Laravel 12 should remain on the 1.x package line.
Installation
Install the current stable release with:
composer require cieplik206/laravel-bir-regon:^2.0
Add your BIR API key to .env:
BIR_API_KEY=your-api-key
To reject NIP and REGON values with invalid Polish checksums before any GUS request, opt in explicitly:
BIR_IDENTIFIER_VALIDATION=checksum
The official public sandbox key is configured by default. Override it only when GUS provides a different test key:
BIR_SANDBOX_API_KEY=your-test-key
The sandbox uses a separate, mutable test dataset. Its records may lag production and may be incomplete, artificial, or anonymized. A missing or different sandbox result does not establish the current production registry state.
Corporate networks may route both production and sandbox traffic through an explicit proxy:
BIR_PROXY_URL=https://proxy.example.com:8443 BIR_PROXY_USERNAME=proxy-user BIR_PROXY_PASSWORD=proxy-password
Proxy credentials are optional, but the username and password must be set
together and are accepted only with an https:// proxy. Anonymous http://
proxies remain supported, but their client-to-proxy link is not protected by
TLS. See the
configuration guide
for validation, TLS, and ambient proxy behavior.
Laravel discovers the package service provider automatically. You may optionally publish the configuration file:
php artisan vendor:publish --tag=bir-regon-config
Version 2 is intentionally breaking: singular identifier searches now return
collections, closed GUS fields use strict enums, full reports include a typed
normalized DTO alongside their raw rows, and Laravel enables a shared-cache
request limiter by default. Direct BirClient construction and the old
GusApi-specific extension points also changed, and direct
NativeSoapTransport construction requires an explicit request limiter. See
UPGRADE-2.0.md before upgrading from 1.x.
See the installation and configuration guides for all available options.
Quick start
Search by one identifier with the facade:
use cieplik206\BirRegon\Facades\BirRegon; $byNip = BirRegon::forNip('1234567890')->get(); // Collection<CompanyData> $byRegon = BirRegon::forRegon('123456789')->get(); $byKrs = BirRegon::forKrs('0000123456')->get(); $company = BirRegon::forNip('1234567890')->sole(); // CompanyData
Even a single NIP, REGON, or KRS can identify more than one GUS record, for
example activity recorded in separate silos. get() and search() therefore
remain the safe plural default and return every result as an
Illuminate\Support\Collection; neither method silently selects a silo.
Builder sole() returns one CompanyData, throws BirNotFoundException for
no rows, and throws BirAmbiguousSearchResultException for multiple rows. Use
it only when the application's domain requires exactly one result.
The same API is available through dependency injection:
use cieplik206\BirRegon\BirRegonService; use cieplik206\BirRegon\Data\CompanyData; use Illuminate\Support\Collection; class FindCompany { public function __construct( private BirRegonService $birRegon, ) {} /** @return Collection<int, CompanyData> */ public function handle(string $nip): Collection { return $this->birRegon->forNip($nip)->get(); } }
Search response fields with a closed GUS vocabulary use EntityType, Silo,
and nullable NipStatus enums. regon14 remains null unless GUS actually
returns a 14-digit REGON; the package never derives it by padding another
identifier. EntityType::isNaturalPersonFamily() includes natural persons and
their local units; isLegalUnitFamily() includes legal units and their local
units.
Checksum validation is intentionally optional because it is stricter than the
GUS request contract. Laravel defaults to BIR_IDENTIFIER_VALIDATION=format,
which checks exact digit lengths only. Set it to checksum to apply the
existing NIP and REGON checksum algorithms automatically to production and
sandbox searches, batches, and report lookups:
BIR_IDENTIFIER_VALIDATION=checksum
KRS has no checksum algorithm and remains a strict 10-digit format check in
both modes. A valid checksum does not prove that an identifier exists or that
an entity is active. The client accepts undecorated digit strings and does not
remove PL, spaces, or dashes.
Package exceptions do not repeat NIP, REGON, or KRS values in their messages, public properties, or native stack-trace arguments. Log the identifier only when the application's own data-protection policy allows it, and pass it as structured context rather than rebuilding an exception message.
Production is the default. Select the isolated GUS test client before building a sandbox request:
$companies = BirRegon::sandbox() ->forNip('7740001454') ->get();
Production and sandbox keep separate credentials and authenticated sessions. Multiple builders created from the same service reuse the appropriate session. Each isolated client also reuses its cURL connection, DNS cache, and TLS session while clearing request bodies and SID headers between calls.
The Laravel integration enables a cache-backed request limiter by default.
External acquisitions pace second-level debt for no more than one second.
Inside one search/report recovery scope, each internal acquisition after the
first reservation may pace for up to seven seconds; minute and hour exhaustion
always fails fast. BirRateLimitException::retryAfterSeconds() can drive queue
backoff. Multi-host applications should use one shared Redis store. See the
rate-limit guide.
Explicit logout is optional, but available when an application wants to end the current GUS session before its container scope ends:
BirRegon::logout(); BirRegon::sandbox()->logout();
Production and sandbox logout independently. The local SID is always cleared, including when GUS returns an error.
Queued jobs should store only operation inputs such as a NIP, REGON, or KRS,
then resolve BirRegonService in handle(). Do not store BirClient,
BirRegonService, or a request builder on a job. Their serialized form
intentionally omits all state, including credentials and identifiers.
Deserialization produces an inert tombstone that throws LogicException when
used.
See error handling
for an example.
Every public string received from GUS is untrusted, including CompanyData,
raw and normalized report data, DiagnosticsData::$message, and
ServiceStatusData::$message. Mapping does not sanitize it. Escape HTML, bind
SQL values, allowlist http/https links, validate mailto: addresses,
neutralize CSV/XLSX formula prefixes, and normalize control plus Unicode
format/bidirectional characters and bound length before logging to prevent log
forging. See
Data objects.
Documentation
The complete documentation is available on the documentation website:
- Installation
- Configuration
- Basic usage
- Batch searches
- Full and bulk reports
- Data objects
- Request limits
- Service status and diagnostics
- Error handling
- Testing
- Laravel Boost support
- Extending the package
AI tools can use the
llms.txt documentation index.
Testing
Run the isolated test suite:
composer test
The package also contains an opt-in integration suite that performs real requests against the GUS test environment:
composer test:sandbox
See the testing guide for details.
Laravel Boost support
The package ships the bir-regon-development skill for
Laravel Boost. It teaches supported AI
agents the fluent query API, report workflow, exception hierarchy, and sandbox
testing conventions used by this package.
Install and configure Boost in the consuming Laravel application:
composer require laravel/boost --dev php artisan boost:install
If Boost was already installed before Laravel BIR REGON, discover the new package skill with:
php artisan boost:update --discover
Boost detects skills shipped by Composer packages and offers to install them for the AI agents configured in the application. The integration is optional: Laravel BIR REGON does not require Boost at runtime.
See the Laravel Boost support guide for details.
Changelog
Please see the changelog for information about recent changes.
Contributing
Please see Contributing for details.
Maintenance and support
This package was created for and is used in the maintainer's own projects. It is shared publicly in case it is useful to other Laravel developers and is maintained on a best-effort basis. There is no commercial support, SLA, guaranteed response time, or commitment to implement requested changes.
Bug reports and focused pull requests are welcome, but opening an issue does not guarantee a response or fix. See the support policy for the full maintenance expectations. Suspected vulnerabilities must instead follow the private process in SECURITY.md.
Security
Please review the security policy to report vulnerabilities.
Credits
- Statistics Poland (GUS) for the BIR API, documentation, and public sandbox
spatie/laravel-datafor typed data objects
License
The MIT License. Please see the license file for more information. Third-party dependencies retain their respective licenses; see the third-party notices.