cieplik206/laravel-bir-regon

Laravel client for the Polish GUS BIR/REGON API

v2.1.0 2026-08-24 15:23 UTC

README

A fluent Laravel client for the Polish GUS BIR/REGON SOAP API.

Read the full documentation →

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:

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

License

The MIT License. Please see the license file for more information. Third-party dependencies retain their respective licenses; see the third-party notices.