crakter / bringapi
PHP wrapper for Bring's developer APIs (Shipping Guide, Booking, Tracking, Reports, Postal Code, Address, Pickup Point, Modify Delivery, Order Management).
Requires
- php: >=8.2.0
- guzzlehttp/guzzle: >=7.9.2
Requires (Dev)
- friendsofphp/php-cs-fixer: >=3.60.0
- phpunit/phpunit: >=11.2.8
- rector/rector: ^1.1
Suggests
- phpoffice/phpexcel: Allows for convertion of response to JSON/array
- dev-master / 4.x-dev
- 3.0.3
- 3.0.2
- 3.0.1
- 3.0.0
- 2.0.0
- 1.0.2
- 1.0.1
- 1.0.0
- dev-claude/express-nordic-price-codes-T9Qzd
- dev-claude/bring-api-http-405-gkdsp
- dev-claude/brave-bardeen-S4zZM
- dev-dependabot/github_actions/actions/checkout-6
- dev-claude/festive-albattani-m0Hw6
- dev-dependabot/composer/dev-tooling-5468a0ad54
- dev-dependabot/github_actions/ramsey/composer-install-4
- dev-dependabot/github_actions/actions/upload-artifact-7
- dev-dependabot/github_actions/actions/deploy-pages-5
- dev-dependabot/github_actions/codecov/codecov-action-6
- dev-dependabot/github_actions/actions/upload-pages-artifact-5
- dev-claude/busy-meitner-f24NZ
- dev-dependabot/composer/friendsofphp/php-cs-fixer-3.0.1
- dev-dependabot/composer/phpunit/phpunit-8.5.19
- dev-dependabot/add-v2-config-file
This package is auto-updated.
Last update: 2026-06-03 09:45:11 UTC
README
A PHP client library for Bring's developer APIs: Shipping Guide, Booking, Tracking, Reports, Postal Code, the new Address API, Pickup Point, Modify Delivery, and Order Management (REST).
Used in production by a large Norwegian wholesaler.
Install
composer require crakter/bringapi
Requirements
- PHP 8.2 or newer
- A PSR-18 HTTP client (Guzzle 7 is the suggested default)
simplexmlextension (built-in on most distributions)phpoffice/phpspreadsheetonly if you call Reports endpoints that return XLS
Supported APIs
| API | Coverage | Bring docs |
|---|---|---|
| Shipping Guide (v2) | price / delivery time / products | link |
| Booking | book, pickup order, customers | link |
| Tracking | track, signature image | link |
| Reports | list, generate, status, download, invoices | link |
| Postal Code (legacy) | single lookup | link |
| Address (new) | postal-code lookup, suggestions, mailbox-delivery dates | link |
| Pickup Point | all / by id / by postal code / by location (NO/SE/DK/FI only) | link |
| Modify Delivery | stop, change address, update contact (NO/SE/DK only) | link |
| Order Management (REST) | get order, packaging list | link |
The SOAP variant of Order Management is intentionally out of scope.
Quick start
use Bring\Api\ApiClient; use Bring\Api\Auth\Credentials; use Bring\Api\Enum\Country; $bring = ApiClient::withCredentials(new Credentials( uid: 'me@example.com', apiKey: getenv('BRING_API_KEY'), clientUrl: 'https://example.com', )); // Modern address lookup $result = $bring->address()->postalCode(Country::NO, '0150'); echo $result->city; // "OSLO" // Pickup points near a postal code foreach ($bring->pickupPoint()->byPostalCode(Country::NO, '0150')->pickupPoints as $pp) { echo "{$pp->name} — {$pp->address}\n"; } // Tracking $tracking = $bring->tracking()->track('TESTPACKAGE-AT-PICKUPPOINT'); echo $tracking->latestEvent()?->description;
Test mode
Calls that support X-Bring-Test-Indicator (Booking, Modify Delivery) are
toggled at the facade:
$bring = ApiClient::withCredentials($creds)->withTestMode(true); // Every request now carries X-Bring-Test-Indicator: true
Booking a shipment
use Bring\Api\Dto\{Address, Contact, Dimensions, Package}; use Bring\Api\Endpoint\Booking\BookingRequest; use Bring\Api\Enum\{Country, Product}; $request = BookingRequest::single( schemaVersion: '1', customerNumber: 'PARCELS_NORWAY-10001234567', product: Product::HOME_DELIVERY_PARCEL, sender: new Address( name: 'Acme AS', addressLine: 'Sandakerveien 24c', addressLine2: null, postalCode: '0473', city: 'Oslo', countryCode: Country::NO, contact: new Contact(name: 'Pickup Person', phoneNumber: '+4799999999'), ), recipient: new Address( name: 'John Doe', addressLine: 'Storgata 1', addressLine2: null, postalCode: '5003', city: 'Bergen', countryCode: Country::NO, ), packages: [new Package( weightInKg: 2, dimensions: new Dimensions(lengthInCm: 30, widthInCm: 20, heightInCm: 15), )], ); $resp = $bring->booking()->book($request); foreach ($resp->consignments as $c) { echo "Consignment {$c->confirmation}\n"; }
Credentials and logging
Credentials wraps the API key behind #[\SensitiveParameter] (PHP 8.2+
scrubs it from stack traces) and masks it in print_r / var_dump output —
debug dumps only show a SHA-256 fingerprint.
Pass any PSR-3 logger to ApiClient::withCredentials() and it is automatically
wrapped in a RedactingLogger that strips X-Mybring-* headers and the raw
API key from every log line:
$bring = ApiClient::withCredentials($creds, logger: $monolog);
BringApiException never embeds the raw response body in getMessage() —
Bring occasionally echoes credentials in error envelopes. Callers that want
the response body can call BringApiException::getResponse() explicitly.
Error handling
use Bring\Api\Exception\{BringApiException, BringTransportException, BringException}; try { $bring->shippingGuide()->price($request); } catch (BringApiException $e) { // Bring returned 4xx/5xx — parsed error codes in $e->getErrors() error_log("Bring rejected request (HTTP {$e->getStatusCode()})"); foreach ($e->getErrors() as $err) { error_log(" {$err->code}: {$err->message}"); } } catch (BringTransportException $e) { // PSR-18 network failure (DNS, TLS, timeout); $e->getPrevious() has the cause } catch (BringException $e) { // Catch-all for anything this library throws }
v3 → v4 migration
See UPGRADE-4.0.md for the full mapping. v3 classes
(Crakter\BringApi\*) still ship and still work — they are marked
@deprecated and will be removed in 5.0.
Examples
Set credentials in your environment first:
export BRING_UID="me@example.com" export BRING_API_KEY="1234abc-abcd-1234-5678-abcd1234abcd" export BRING_CUSTOMER_NUMBER="PARCELS_NORWAY-10001123123"
Then run any example from the project root:
php examples/v4_PostalCode.php 0150
php examples/v4_PickupPoint.php 0150
php examples/v4_Tracking.php TESTPACKAGE-AT-PICKUPPOINT
php examples/v4_ShippingGuidePrice.php 0150 5003
php examples/v4_BookAndPickup.php # uses test mode, no labels generated
Development
composer install composer qa # full gate: cs + phpstan + psalm + phpunit composer test # all tests (legacy + v4) composer test-coverage # coverage in coverage/ + coverage.xml composer phpstan # PHPStan level 8 on v4 composer psalm # Psalm errorLevel 4 on v4 composer cs # php-cs-fixer dry run composer docs # build API docs into docs/build
API documentation
Generated with phpDocumentor 3 (the abandoned Sami
generator was dropped in 4.0). bin/build-docs downloads the official
phar into tools/phpdoc.phar on first run — we deliberately do NOT
require phpDocumentor through Composer because its transitive dependency
tree conflicts with most application stacks.
composer docs # build into docs/build composer docs-clean # wipe + rebuild bin/build-docs --force # any extra phpdoc flags pass through
Open docs/build/index.html in a browser, or let CI publish it:
.github/workflows/docs.yml builds on every push to master/main and
deploys to GitHub Pages (enable Pages in repo settings → Pages → Source =
GitHub Actions to activate). Every workflow run also uploads the rendered
docs as an artifact named api-docs.
Project documents
- CHANGELOG.md — release history (Keep a Changelog format)
- UPGRADE-4.0.md — v3 → v4 migration guide
- SECURITY.md — vulnerability reporting
- CONTRIBUTING.md — coding standards and PR process
License
MIT