Integracja InPost w sklepie internetowym: Paczkomaty i API ShipX
Paczkomaty to w polskim e-commerce standard, a nie wyróżnik. Dla wielu klientów brak InPostu w checkoucie to powód, żeby kupić gdzie indziej. Dobra wiadomość: API ShipX jest jednym z lepiej zaprojektowanych API logistycznych na naszym rynku i integrację da się zrobić porządnie, bez wtyczek-kombajnów. Poniżej przechodzimy przez cały przepływ, którego używamy we wdrożeniach: od wyboru punktu po etykietę i statusy.
Jak to działa w całości
Zanim wejdziemy w szczegóły, pełny obraz. Integracja InPost to cztery klocki, które muszą się spiąć:
- Wybór punktu w checkoucie: klient wskazuje Paczkomat na mapie (Geowidget) albo wybiera kuriera.
- Utworzenie przesyłki: sklep wysyła do ShipX dane odbiorcy, wymiary paczki i usługę.
- Etykieta: po opłaceniu oferty ShipX zwraca PDF (albo ZPL pod drukarki termiczne), który drukuje magazyn.
- Statusy: sklep śledzi, co się dzieje z paczką, i aktualizuje zamówienie oraz maile do klienta.
Każdy z tych klocków da się spartaczyć osobno, więc przejdźmy po kolei.
Wybór Paczkomatu: Geowidget, nie własna mapa
Pierwszy odruch bywa taki, żeby pobrać listę punktów z API i wyświetlić je na własnej mapie. To ślepa uliczka: punktów jest kilkadziesiąt tysięcy, zmieniają się codziennie, a InPost i tak udostępnia gotowy, darmowy Geowidget. To web component, który osadza się jednym tagiem:
<inpost-geowidget
token="TWÓJ_TOKEN_GEOWIDGETU"
language="pl"
config="parcelCollect"
onpoint="onPointSelected"
></inpost-geowidget>
Po wybraniu punktu dostajesz zdarzenie z obiektem punktu. Najważniejsze
pole to name, czyli identyfikator w stylu KRA012, który za chwilę
przekażemy do ShipX. W sklepach na Medusa.js trzymamy go w metadanych
metody dostawy koszyka, więc backend widzi wybór klienta bez żadnej
dodatkowej magii.
Dwie rzeczy, o których łatwo zapomnieć:
- Token Geowidgetu to inny token niż ShipX: generuje się go osobno w Managerze Paczek i jest jawny (działa w przeglądarce), więc nie ma co go „ukrywać”.
- Walidacja po stronie backendu: identyfikator punktu z frontendu traktujemy jak każde inne dane od użytkownika. Przed utworzeniem przesyłki sprawdzamy, że punkt istnieje i przyjmuje paczki.
Tworzenie przesyłki w ShipX
ShipX ma dwa środowiska: produkcyjne i sandbox. Zaczynamy zawsze od sandboxa, który działa bez umowy z InPost i pozwala przećwiczyć wszystko, łącznie z błędami walidacji.
Przesyłkę tworzy się jednym żądaniem POST na endpoint organizacji:
POST /v1/organizations/{organization_id}/shipments
Authorization: Bearer TWÓJ_TOKEN_SHIPX
Content-Type: application/json
{
"receiver": {
"email": "klient@example.com",
"phone": "500600700"
},
"parcels": [{ "template": "small" }],
"service": "inpost_locker_standard",
"custom_attributes": {
"target_point": "KRA012"
},
"reference": "ZAM-2026-01234"
}
Kilka praktycznych uwag, które oszczędzą godzin debugowania:
- Szablony paczek (
small,medium,large) odpowiadają gabarytom A/B/C Paczkomatu. Jeśli sprzedajesz produkty o nietypowych wymiarach, podajeszdimensionsiweightjawnie, ale przy Paczkomatach i tak obowiązują limity gabarytów, więc szablon jest zwykle prostszy. referenceto Twój przyjaciel: wpisujemy tam numer zamówienia ze sklepu. Widać go potem na etykiecie i w Managerze Paczek, co ratuje życie przy reklamacjach.- Telefon odbiorcy musi być polskim numerem komórkowym: na ten numer idzie SMS z kodem odbioru. Walidujcie to w checkoucie, nie dopiero w odpowiedzi błędu z ShipX.
- Dla kuriera zamiast
target_pointpodaje się pełny adres odbiorcy, a usługę zmienia nainpost_courier_standard. Reszta przepływu jest identyczna. To duża zaleta ShipX.
Po utworzeniu przesyłka przechodzi przez cykl ofert: ShipX wycenia usługę, a sklep kupuje wybraną ofertę. Przy prostych konfiguracjach z jedną usługą da się to zautomatyzować do zera: tworzysz przesyłkę, czekasz na status z gotową ofertą i od razu ją kupujesz.
Etykieta: PDF dla biura, ZPL dla magazynu
Po opłaceniu przesyłki (status confirmed) pobiera się etykietę:
GET /v1/shipments/{shipment_id}/label?format=pdf
Format pdf wystarcza, gdy etykiety drukuje się z przeglądarki. Przy
większych wolumenach warto od razu pomyśleć o zpl, bo drukarki termiczne
(Zebra i klony) przyjmują go bezpośrednio, bez renderowania PDF-a, co
przy kilkuset paczkach dziennie robi realną różnicę.
We wdrożeniach B2B podpinamy pobieranie etykiety pod zmianę statusu zamówienia: magazyn oznacza zamówienie jako spakowane, system tworzy przesyłkę, kupuje ofertę, pobiera etykietę i odsyła ją do wydruku. Nikt niczego nie przeklikuje ręcznie. I o to chodzi.
Statusy: skąd sklep wie, że paczka jedzie
ShipX wystawia słownik statusów (endpoint /v1/statuses) i pozwala
śledzić przesyłkę po numerze trackingowym. W praktyce sprawdzają się dwa
podejścia:
| Podejście | Jak działa | Kiedy wybrać |
|---|---|---|
| Polling | Cykliczne odpytywanie o statusy aktywnych przesyłek | Mniejsze wolumeny, prostota |
| Webhooki | InPost wypycha zmiany statusów na Twój endpoint | Duże wolumeny, aktualizacje niemal na żywo |
Niezależnie od podejścia: mapujcie statusy InPostu na własne, prostsze statusy zamówienia. Klienta nie interesuje różnica między „przyjęta w oddziale” a „w drodze do regionu”. Interesuje go „nadana”, „czeka w Paczkomacie” i „odebrana”. Mail z kodem odbioru wysyła InPost, ale dobry sklep i tak pokazuje status w koncie klienta.
Jak to wygląda w Medusa.js
W Medusa v2 logistykę spina się przez moduł fulfillmentu: provider implementuje kilka metod (utworzenie przesyłki, anulowanie, pobranie dokumentów), a resztą steruje rdzeń platformy. Szkielet wygląda tak:
class InpostFulfillmentProvider extends AbstractFulfillmentProviderService {
static identifier = "inpost";
async createFulfillment(data, items, order, fulfillment) {
const shipment = await this.shipx.createShipment({
receiver: mapReceiver(order),
parcels: mapParcels(items),
service: data.service, // locker albo courier
targetPoint: data.target_point,
reference: order.display_id,
});
return { data: { shipment_id: shipment.id } };
}
async getFulfillmentDocuments(data) {
return this.shipx.getLabel(data.shipment_id, "zpl");
}
}
To celowo szkic, nie gotowiec. Sedno w tym, że integracja logistyczna
w Medusie jest modułem, nie wtyczką z marketplace’u. Macie pełną
kontrolę nad tym, kiedy przesyłka powstaje, co trafia do reference
i jak wygląda obsługa błędów. Na tej samej zasadzie zbudowaliśmy wysyłkę
w naszym pokazowym sklepie demo.koda.plus.
Można tam poklikać pełny checkout z wyborem Paczkomatu.
Najczęstsze wtopy z wdrożeń
- Brak obsługi błędów walidacji: ShipX potrafi odrzucić przesyłkę (np. zły telefon). Sklep musi to pokazać obsłudze, a nie połknąć.
- Etykieta generowana przy złożeniu zamówienia: za wcześnie. Paczka może się nie spakować tego dnia, a niektóre oferty mają termin ważności. Etykieta powinna powstawać, gdy magazyn faktycznie pakuje.
- Jeden token na sandbox i produkcję: to dwa osobne środowiska z osobnymi tokenami. Trzymajcie je w zmiennych środowiskowych i nigdy w repozytorium.
- Punkt wybrany raz na zawsze: Paczkomat bywa przepełniony albo czasowo niedostępny. Warto obsłużyć redirect przesyłki i komunikat dla klienta, zamiast udawać, że problem nie istnieje.
Jeśli zamiast składać to wszystko samodzielnie wolicie mieć logistykę spiętą z resztą sklepu (od checkoutu, przez ERP, po maile), to dokładnie ten zakres robimy przy sklepach i hurtowniach na Medusa.js.