beziworld / laravel-inpost
InPost ShipX integration for Laravel: shipments, parcel lockers (Paczkomaty), labels, tracking and status webhooks.
Requires
- php: ^8.3
- ext-json: *
- guzzlehttp/guzzle: ^7.8
- illuminate/contracts: ^12.0|^13.0
- illuminate/http: ^12.0|^13.0
- illuminate/routing: ^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 16:36:32 UTC
README
InPost ShipX for Laravel: shipments to parcel lockers (Paczkomaty) and by courier, labels, courier pickups, tracking, point search, the Geowidget map and status webhooks.
Installation
composer require beziworld/laravel-inpost
php artisan vendor:publish --tag=inpost-config # optional
INPOST_TOKEN=your-shipx-token # Manager Paczek > My account > API INPOST_ORGANIZATION_ID=12345 INPOST_SANDBOX=true # sandbox-api-shipx-pl.easypack24.net INPOST_GEOWIDGET_TOKEN=your-public-geo-token
Points, tracking and statuses are public and work without a token.
Parcel locker in the checkout
{{-- checkout.blade.php --}} {{ InPost::geowidget('onInPostPointSelected', 'parcelCollect') }} <input type="hidden" name="inpost_point" id="inpost_point"> <script> document.addEventListener('onInPostPointSelected', (event) => { document.getElementById('inpost_point').value = event.detail.name; }); </script>
Use parcelCollectPayment for cash on delivery or parcelCollect247 for weekend deliveries. Validate the choice on
the server:
$point = InPost::point($request->input('inpost_point')); abort_if($point === null || ! $point->isOperating(), 422, 'Choose an active parcel locker.');
Shipments
use Beziworld\InPost\Data\ShipmentRequest; use Beziworld\InPost\Facades\InPost; // Parcel locker, size B, cash on delivery $shipment = InPost::createShipment(ShipmentRequest::toLocker( targetPoint: $order->inpost_point, // e.g. "KRA010" email: $order->email, phone: $order->phone, template: 'medium', reference: $order->number, codAmount: $order->cod ? $order->total : null, )); $order->update(['inpost_shipment_id' => $shipment->id]);
Courier shipments and full control:
use Beziworld\InPost\Data\{Address, Parcel, Peer, ShipmentRequest}; use Beziworld\InPost\Enums\Service; InPost::createShipment(new ShipmentRequest( service: Service::CourierStandard, receiver: new Peer(email: 'jan@example.com', phone: '500100200', firstName: 'Jan', lastName: 'Kowalski', address: new Address('Prosta', '1', 'Warszawa', '00-001')), parcels: [Parcel::dimensions(length: 400, width: 300, height: 200, weight: 3.5)], insuranceAmount: 500, reference: 'order-1001', additionalServices: ['sms', 'email'], ));
Creation is asynchronous: the shipment starts as created and becomes confirmed shortly after (with a tracking
number). Download the label once it is confirmed:
$shipment = InPost::shipment($order->inpost_shipment_id); if ($shipment->isConfirmed()) { return response(InPost::label($shipment->id, 'pdf', 'A6'), 200, ['Content-Type' => 'application/pdf']); }
Other calls: InPost::labels([1, 2, 3]) (up to 100 labels in one file), InPost::shipments(['status' => 'confirmed']),
InPost::cancelShipment($id) (only before confirmation) and
InPost::createDispatchOrder([$id1, $id2], new Address(...), 'Warehouse', '500100200') for a courier pickup.
Tracking and points
$tracking = InPost::tracking('620000000000000000000000'); $tracking->status; // "ready_to_pickup" $tracking->events; // newest first: status, location, at InPost::points(['city' => 'Kraków', 'type' => 'parcel_locker', 'payment_available' => true]); InPost::points(['relative_point' => '50.0614,19.9366', 'max_distance' => 1000]); // nearest, with distance in metres InPost::statuses(); // ['delivered' => 'Dostarczona.', ...]
Webhooks
Register https://your-app.com/inpost/webhook in Manager Paczek. The package answers the GET check, accepts POSTs
only from the InPost network (91.216.25.0/24) and dispatches ShipmentStatusChanged:
use Beziworld\InPost\Events\ShipmentStatusChanged; Event::listen(function (ShipmentStatusChanged $event) { $order = Order::where('inpost_shipment_id', $event->shipmentId)->first(); if ($event->status === 'delivered') { // ShipX webhooks are not signed: confirm important changes with the API $order?->markAsDelivered(InPost::shipment($event->shipmentId)->status === 'delivered'); } });
Behind a load balancer configure Laravel trusted proxies so that the IP check sees the real sender.
Exceptions
ApiException (error() such as validation_failed, details() with field errors, httpStatus()) and
InvalidConfiguration, both extending InPostException.
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-przelewy24 · laravel-payu · laravel-paynow · laravel-tpay · laravel-autopay · laravel-company-data
License
MIT. See LICENSE.md. This package is not affiliated with InPost S.A.