beziworld / laravel-poczta-polska
Laravel client for Poczta Polska: e-Nadawca shipping API (Pocztex, parcels, COD, pickup points, labels, envelopes) and the public parcel tracking web service, without ext-soap.
Package info
github.com/Beziworld/laravel-poczta-polska
pkg:composer/beziworld/laravel-poczta-polska
Requires
- php: ^8.3
- ext-dom: *
- ext-json: *
- guzzlehttp/guzzle: ^7.8
- illuminate/contracts: ^12.0|^13.0
- illuminate/http: ^12.0|^13.0
- illuminate/support: ^12.0|^13.0
Requires (Dev)
- larastan/larastan: ^3.0
- laravel/pint: ^1.18
- orchestra/testbench: ^10.0|^11.0
- pestphp/pest: ^3.7|^4.0
- pestphp/pest-plugin-laravel: ^3.0|^4.0
- phpstan/phpstan-strict-rules: ^2.0
Suggests
None
Provides
None
Conflicts
None
Replaces
None
This package is auto-updated.
Last update: 2026-11-04 17:35:10 UTC
README
Poczta Polska client for Laravel:
- shipments through the e-Nadawca (Elektroniczny Nadawca) WebAPI: buffer, labels and envelope workflow
- typed builders for Pocztex 2.0 Kurier, Pocztex 2.0 Na Dziś, Pocztex Kurier 48, Paczka Pocztowa and registered letters, with cash on delivery, insurance, declared value, multi-parcel shipments and delivery to a point ("Odbiór w Punkcie", Automat Pocztex lockers)
- labels (PDF or ZPL), posting book, envelope status and contents, posting offices, contract cards, buffers
- post offices, partner points and lockers (
getPlacowkiPocztowe) - parcel tracking through the public "Śledzenie przesyłek" web service (WS-Security), single and batch, with typed events, delivered and awaiting-pickup helpers
- multiple accounts (named connections and runtime credentials)
- SOAP over the Laravel HTTP client: no
ext-soap, everything fakeable withHttp::fake()
Why another package?
Existing PHP packages are generated ext-soap class dumps of the e-Nadawca WSDL (printu/elektroniczny-nadawca,
bitbag/pp-client) or tracking-only clients. This one is a Laravel package covering both services with typed shipment
builders and DTOs, multiple accounts, Http::fake() support and no ext-soap requirement.
Installation
composer require beziworld/laravel-poczta-polska
php artisan vendor:publish --tag=poczta-polska-config # optional
POCZTA_POLSKA_USERNAME=... # e-Nadawca login and password (HTTP Basic) POCZTA_POLSKA_PASSWORD=... POCZTA_POLSKA_SANDBOX=false # true = integration environment int-e-nadawca.api.poczta-polska.pl (separate account) POCZTA_POLSKA_POSTING_OFFICE=260578 # default urzadNadania for sendEnvelope, see postingOffices() POCZTA_POLSKA_LABEL_FORMAT=PDF_FORMAT # or ZPL_FORMAT POCZTA_POLSKA_TRACKING_USERNAME= # empty = public account sledzeniepp / PPSA (development, 1 shipment per request) POCZTA_POLSKA_TRACKING_PASSWORD= POCZTA_POLSKA_TRACKING_LANGUAGE=pl # pl or en event names
e-Nadawca credentials are only needed for shipping; tracking works on its own.
Envelope workflow
e-Nadawca collects shipments in a buffer. Add shipments, print their labels and hand the buffer over as an envelope on the same day as the first shipment was added.
use Beziworld\PocztaPolska\Data\Address; use Beziworld\PocztaPolska\Data\CashOnDelivery; use Beziworld\PocztaPolska\Data\Insurance; use Beziworld\PocztaPolska\Data\PocztexCourier; use Beziworld\PocztaPolska\Enums\PocztexFormat; use Beziworld\PocztaPolska\Facades\PocztaPolska; PocztaPolska::clearEnvelope(); // recommended before the first shipment of a session $added = PocztaPolska::addShipment(new PocztexCourier( receiver: new Address('Anna Kowalska', 'Długa', '5', 'Kraków', '30-001', apartmentNumber: '3', email: 'anna@example.com', mobile: '600700800'), weight: 2500, // grams format: PocztexFormat::M, cashOnDelivery: new CashOnDelivery(149.99, '25101000000000000000000000', 'Order 1001'), // PLN insurance: new Insurance(1000), // a level from insuranceLevels() contents: 'Books', reference: 'ORDER-1001', )); $added->trackingNumber; // PX6000279796 $added->guid; // generated 32-character GUID (or the one you passed) $pdf = PocztaPolska::labels($added->guid); // address label $envelope = PocztaPolska::sendEnvelope(); // configured posting office, or sendEnvelope(260578) PocztaPolska::envelopeStatus($envelope->id); // EnvelopeStatus::Sent, Accepted, ... PocztaPolska::envelopeContents($envelope->id); // list<EnvelopeShipment> PocztaPolska::outboxBook($envelope->id); // posting book PDF
Other products: PocztexToday (Pocztex 2.0 Na Dziś), BusinessParcel (Pocztex Kurier 48), PostalParcel
(Paczka Pocztowa), RegisteredLetter (przesyłka polecona). Extra parcels of a multi-parcel Pocztex shipment go into
additionalParcels: [new PocztexParcel(1200)].
addShipments([...]) sends up to 500 shipments at once and returns one AddedShipment per shipment; rejected ones
carry their errors instead of throwing. removeShipments($guids) removes shipments from the buffer, buffers() and
createBuffer() manage several buffers.
Delivery to a point
use Beziworld\PocztaPolska\Enums\Voivodeship; $points = PocztaPolska::points(Voivodeship::Mazowieckie, pickupPointsOnly: true); // refresh once a day $points[0]->id; // PNI, e.g. 536966 $points[0]->isLocker(); // Automat Pocztex $points[0]->maxCashOnDelivery; new PocztexCourier(receiver: $address, weight: 1000, format: PocztexFormat::S, pickupPoint: 536966);
Lockers accept limited formats and COD amounts and no "fragile" or content check; e-Nadawca reports these as errors.
Use postingPoint: or channel: ShipmentChannel::ParcelLocker to hand the shipment over at a post office or locker
instead of a courier pickup. pointsByPni([...]) reads points by PNI.
Labels and documents
use Beziworld\PocztaPolska\Enums\PrintFormat; use Beziworld\PocztaPolska\Enums\PrintKind; PocztaPolska::labels([$guid1, $guid2]); // one file PocztaPolska::prints([$guid1, $guid2], separateFiles: true); // list<Label> with guid and content PocztaPolska::prints([$guid], PrintKind::CashOnDeliveryForm); // COD form, customs declaration, ... PocztaPolska::labels($guid, PrintFormat::Zpl);
Tracking
$shipment = PocztaPolska::tracking()->track('PX6000279796'); $shipment->found(); // false when unknown (only shipments with an event in the last 30 days) $shipment->isDelivered(); $shipment->isAwaitingPickup(); // waiting at a post office, point or locker $shipment->state(); // TrackingState::InTransit, ... foreach ($shipment->events as $event) { $event->code; // P_NAD, P_D, P_KWD, ... (map codes, not names) $event->name; $event->occurredAt; $event->unit; } PocztaPolska::tracking()->trackMany(['PX1', 'PX2']); // dedicated account required for more than 1 PocztaPolska::tracking()->trackMany(['PX1'], now()->subWeek(), now()); PocztaPolska::tracking()->maxShipments();
The public credentials (sledzeniepp / PPSA) are published by Poczta Polska for one-off queries and development.
Request a dedicated account for production traffic.
Multiple accounts
// config/poczta-polska.php 'connections' => [ 'default' => [], 'warehouse' => [ 'username' => env('POCZTA_POLSKA_WAREHOUSE_USERNAME'), 'password' => env('POCZTA_POLSKA_WAREHOUSE_PASSWORD'), 'posting_office' => 123456, ], ],
PocztaPolska::connection('warehouse')->addShipment($shipment); PocztaPolska::tracking('warehouse')->track('PX1'); $client = PocztaPolska::using(['username' => $tenant->login, 'password' => $tenant->password]); // runtime credentials
Options outside connections are shared defaults. ENadawcaClient and TrackingClient can also be injected; they
use the default connection.
Errors
| Exception | When |
|---|---|
ApiException |
e-Nadawca returned errors or a SOAP fault: errorNumber() (e.g. 40102 product not on the contract), apiErrors() with number, description, guid, httpStatus() |
TrackingException |
the tracking service rejected a batch (errorNumber() -1 too many shipments, -2 no permission, -3 invalid dates) or answered a fault |
AuthenticationFailed |
wrong credentials (HTTP 401 from e-Nadawca, WS-Security fault from tracking) |
ConnectionFailed |
the service could not be reached |
InvalidConfiguration |
missing credentials or unknown connection |
All extend PocztaPolskaException. Requests are never retried automatically: after a timeout of addShipment or
sendEnvelope, check the buffer (call('getEnvelopeBufor')) or the envelope list before sending again. Any other
operation is available through call($operation, $parameters).
Development
composer install
composer ci # pint --test, phpstan (level 8), pest
Author
Created and maintained by Kamil Ćwiertnia, beziworld.eu.
- E-mail: biuro@beziworld.eu
- Issues: GitHub issues
Need a shipping integration for your shop? Get in touch through beziworld.eu.
Other packages by the author
laravel-inpost · laravel-dpd · laravel-dhl-parcel · laravel-orlen-paczka · laravel-furgonetka · laravel-apaczka
License
MIT. See LICENSE.md. This package is not affiliated with Poczta Polska S.A.