laravel-poczta-polska maintained by beziworld
Laravel Poczta Polska
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.