Search by

beziworld / laravel-poczta-polska

kamcw

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

Homepage

Issues

pkg:composer/beziworld/laravel-poczta-polska

Statistics

Installs: 1

Dependents: 0

Suggesters: 0

Stars: 0

v1.0.0 2026-11-04 17:34 UTC

This package is auto-updated.

Last update: 2026-11-04 17:35:10 UTC


README

tests Latest Version License

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 with Http::fake()

Polska wersja dokumentacji

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.

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.