API LM Logistic

Wersja z 09.11.2026. API pozwala z Twojego programu albo sklepu wycenić przesyłkę, zamówić wybraną ofertę, pobrać etykietę, śledzić przesyłkę i poprosić o jej anulowanie. Widzisz te same ceny i przewoźników co w portalu klienta, a zamówienia z API rozliczamy tak samo jak zamówienia z portalu.

Kto może korzystać. Firmy z płatnością odroczoną. Firma płacąca z góry może wyceniać, ale zamówienie dostanie odpowiedź 403 PREPAYMENT_REQUIRED, bo API nie ma kroku płatności. Pobranie (COD) nie jest dostępne w API.

Opis wszystkich pól w formacie OpenAPI (do importu np. w Postmanie): openapi.yaml.

Adresy i klucz

ŚrodowiskoAdres bazowyKlucz
Testhttps://test.lmlogistic.pl/api/partner/v1testowy, działa tylko tutaj
Produkcjahttps://klient.lmlogistic.pl/api/partner/v1produkcyjny, od biura po zakończeniu testów

Klucz ma postać lmp_ i 40 znaków. Wysyłaj go w każdym zapytaniu:

Authorization: Bearer lmp_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

Klucz trzymaj tylko na swoim serwerze, nie wstawiaj go do kodu strony w przeglądarce. Każde zapytanie ma format JSON (UTF-8). Kwoty podajemy w PLN (albo w walucie, w której rozliczamy Twoją firmę: pole currency), wagi w kg, wymiary w cm, daty yyyy-MM-dd, godziny HH:mm.

Limit: 300 zapytań na minutę z jednego adresu IP (po przekroczeniu odpowiedź 429), zapytanie do 1 MB.

Środowisko testowe

Działa tak samo jak produkcja, ale nic w nim nie jest prawdziwe:

Śledzenie przesyłki z symulatora liczy się od nadania, a nowe zdarzenia pojawiają się w API przy odświeżeniu, które działa raz na godzinę:

Po czasiestatusZnaczenie
od razuSIM_CREATEDPrzyjęto zlecenie
10 minutSIM_PICKED_UPOdebrano od nadawcy
30 minutSIM_IN_TRANSITW transporcie
1 godzinaSIM_OUT_FOR_DELIVERYW doręczeniu
2 godzinySIM_DELIVEREDDoręczona

Na produkcji statusy mają kody przewoźnika, więc nie opieraj logiki na tych z tabeli. Do wyświetlania klientowi służy pole description.

Szybki start

Sprawdzenie klucza:

curl -s -H "Authorization: Bearer $LM_API_KEY" https://test.lmlogistic.pl/api/partner/v1/ping

Wycena paczki:

curl -s -H "Authorization: Bearer $LM_API_KEY" -H "Content-Type: application/json" \
  -d '{"sender":{"countryCode":"PL","postalCode":"05-500","private":false},"receiver":{"countryCode":"PL","postalCode":"00-950","private":false},"parcelType":"PACK","packages":[{"weightKg":5,"lengthCm":30,"widthCm":20,"heightCm":15}]}' \
  https://test.lmlogistic.pl/api/partner/v1/quotes

Dalej: wybierz offerId z odpowiedzi, wyślij POST /orders, odpytuj GET /orders/{orderId} aż pojawi się numer listu, pobierz etykietę z GET /documents/{documentId}.

Błędy

Kod HTTP mówi, co się stało, a treść ma stały kod błędu i komunikat po polsku:

{ "error": { "code": "VALIDATION", "message": "Brak kodu pocztowego.", "field": "receiver.postalCode" } }
HTTPKodZnaczenie
400VALIDATIONBłędne albo brakujące pole (field wskazuje które)
401UNAUTHORIZEDBrak klucza albo klucz unieważniony
403ORDERS_BLOCKEDZamawianie wstrzymane (zaległe faktury); wycena działa
403PREPAYMENT_REQUIREDFirma płaci z góry, więc nie zamówi przez API; wycena działa
404QUOTE_NOT_FOUND, OFFER_NOT_FOUND, ORDER_NOT_FOUND, PARCEL_NOT_FOUND, DOCUMENT_NOT_FOUNDNie ma albo nie należy do Ciebie
409OFFER_NOT_AVAILABLEWycena zamówiona inną ofertą albo anulowana
422QUOTE_REJECTED, ORDER_REJECTED, CANCEL_REJECTEDReguła biznesowa (komunikat mówi, co poprawić)
429RATE_LIMITZa dużo zapytań
500, 502SERVER_ERROR, UNAVAILABLEBłąd po naszej stronie, spróbuj ponownie

1. Sprawdzenie połączenia

GET /ping zwraca nazwę firmy przypisanej do klucza. Pole environment ma wartość Production tylko na produkcji.

{ "partner": "Twoja Firma Sp. z o.o.", "environment": "Staging", "serverTime": "2026-11-09T08:00:00+00:00" }

2. Wycena

POST /quotes

{
  "sender":   { "countryCode": "PL", "postalCode": "05-500", "private": false },
  "receiver": { "countryCode": "PL", "postalCode": "00-950", "private": true },
  "parcelType": "PACK",
  "packages": [ { "weightKg": 5, "lengthCm": 30, "widthCm": 20, "heightCm": 15 } ],
  "insurance": 500,
  "services": [],
  "description": "Książki"
}

Odpowiedź:

{
  "quoteId": 10235409,
  "offers": [
    {
      "offerId": 10408243,
      "carrier": "UPS Standard",
      "service": "Transport drogowy",
      "priceNet": 61.76, "vat": 14.20, "priceGross": 75.96, "currency": "PLN",
      "validUntil": "2026-11-09T08:07:17+01:00",
      "components": [ { "code": "PACK", "name": "UPS Standard", "net": 61.76, "gross": 75.96 } ],
      "availableServices": [ { "name": "Powiadomienie SMS", "description": null, "priceNet": 1.50 } ]
    }
  ]
}

Oferta jest ważna do validUntil, a gdy pola brak, przez 7 dni. Pusta lista ofert oznacza, że dla tej trasy i wymiarów nie mamy oferty. GET /quotes/{quoteId} zwraca oferty tej samej wyceny jeszcze raz.

3. Zamówienie

POST /orders

{
  "offerId": 10408243,
  "sender":   { "companyName": "Jan Kowalski", "contactPerson": "Jan Kowalski", "email": "jan@example.com", "phone": "+48 600 100 200",
                "street": "Polna", "houseNo": "1", "flatNo": "2", "city": "Piaseczno", "postalCode": "05-500", "countryCode": "PL" },
  "receiver": { "companyName": "Anna Nowak", "contactPerson": "Anna Nowak", "email": "anna@example.com", "phone": "+48 600 200 300",
                "street": "Marszałkowska", "houseNo": "10", "city": "Warszawa", "postalCode": "00-950", "countryCode": "PL" },
  "pickup": { "date": "2026-11-12", "from": "09:00", "to": "15:00" },
  "reference": "ZAM-2026-000123"
}

Odpowiedź 201:

{
  "orderId": 10214332, "orderNumber": "L10214332", "state": "IN_PROGRESS", "reference": "ZAM-2026-000123",
  "parcels": [ { "parcelId": 10235409, "parcelNumber": "L10214332P10235409", "state": "IN_PROGRESS",
                 "waybillNumber": null, "carrier": "UPS", "pickupNumber": null,
                 "priceNet": 61.76, "priceGross": 75.96, "currency": "PLN", "documents": [] } ]
}

Zlecenie od razu trafia do przewoźnika. Numer listu i etykieta pojawiają się zwykle po kilku sekundach: odpytuj GET /orders/{orderId} co kilka sekund, aż waybillNumber i documents się wypełnią (state przesyłki zmienia się z IN_PROGRESS na WAY_BILL).

4. Zlecenie, etykieta, śledzenie

Stany przesyłki: IN_PROGRESS (przekazana do przewoźnika), WAY_BILL (ma numer listu), dalsze stany według przewoźnika, CANCEL (anulowana).

5. Anulowanie

POST /parcels/{parcelId}/cancel z treścią { "reason": "Klient zrezygnował" }:

Dotychczasowe API (/logistic/api/ext)

Klienci, którzy używali API starego systemu (nagłówek client_token), przechodzą na nowy system, zmieniając tylko adres serwera na https://klient.lmlogistic.pl/logistic/api/ext/…. Ścieżki, pola, jednostki (gramy, grosze) i komunikaty zostają bez zmian. Tylko HTTPS.