API
Dokumentacja API i webhooków
Programuj integracje z NavyFlame: odczytuj i zapisuj zamówienia, magazyn, faktury i przesyłki przez REST API, i odbieraj podpisane webhooki o zdarzeniach w czasie zbliżonym do rzeczywistego.
Wprowadzenie
Publiczne API NavyFlame to interfejs typu server-to-server. Każde wywołanie autoryzujesz kluczem API, a odpowiedzi mają stabilny, wersjonowany kształt. Bazowy adres jest w Twojej domenie tenanta:
https://{your-slug}.navyflame.com/api/public/v1Pełną, maszynową specyfikację (OpenAPI 3.1) pobierzesz pod adresem /openapi-public-v1.yaml i zaimportujesz do Postmana, Insomnii lub dowolnego klienta OpenAPI.
Szybki start
Zacznij od utworzenia klucza w panelu (Konto - API) i sprawdzenia połączenia zapytaniem GET /me - nie wymaga żadnego zakresu, wystarczy ważny klucz. Zwraca Twój plan, limity i zakresy klucza.
curl https://{your-slug}.navyflame.com/api/public/v1/me \
-H "Authorization: Bearer nf_live_your_key"Przykładowa odpowiedź:
{
"tenant": "your-slug",
"keyPrefix": "nf_live_abc123",
"scopes": ["orders:read", "orders:write"],
"plan": "Professional",
"rateLimitPerMin": 3000,
"apiVersion": "v1"
}Uwierzytelnianie
Klucz przekazujesz w nagłówku Authorization jako token Bearer (rekomendowane). Dla narzędzi bez wsparcia Bearer działa alias X-API-Key:
Authorization: Bearer nf_live_your_key
# or
X-API-Key: nf_live_your_keyKlucze tworzysz, rotujesz i odwołujesz w panelu. Przechowujemy tylko skrót klucza (SHA-256) - pełną wartość zobaczysz raz przy utworzeniu. Klucz jest redagowany we wszystkich logach. Traktuj go jak hasło i nigdy nie umieszczaj po stronie przeglądarki.
Zakresy (scopes)
Każdy klucz ma przypisane zakresy. Zakres :write obejmuje odpowiadający mu :read. Brak wymaganego zakresu zwraca 403 missing_scope.
| Zakres | Uprawnia do |
|---|---|
| orders:read | Odczyt zamówień (lista, szczegóły, statystyki, historia statusów). |
| orders:write | Zmiana statusu, tworzenie zamówień, wyzwalanie fakturowania. |
| catalog:read | Odczyt katalogu: produkty, magazyny, lokalizacje, rezerwacje, dokumenty magazynowe, zestawy. |
| catalog:write | Pełny zapis katalogu: produkty (CRUD), stany i lokalizacje, magazyny, rezerwacje, dokumenty magazynowe, zestawy. |
| invoices:read | Odczyt faktur i statystyk faktur. |
| shipments:read | Odczyt przesyłek i statystyk wysyłek, plus odczyty pomocnicze kuriera (etykieta PDF, punkty odbioru, usługi, terminy nadania). |
| shipments:write | Lifecycle przesyłek: tworzenie, zakup etykiety kurierskiej (płatny u przewoźnika), anulowanie, odświeżanie trackingu, wysyłka numeru śledzenia do Allegro. |
| shipping:read | Odczyt konfiguracji wysyłki: reguły, strefy ze stawkami, opcje dostawy, nadpisania per produkt, plus kalkulator kosztów. |
| shipping:write | Zapis konfiguracji wysyłki: reguły, strefy i stawki per strefa, opcje dostawy, nadpisania wysyłki per produkt. |
| integrations:read | Odczyt listy konektorów konta (bez sekretów): klucz, id konfiguracji, nazwa, status włączenia i połączenia. Nigdy nie zwraca danych logowania. |
| offers:read | Odczyt ofert marketplace: mapowania produkt-kanał per produkt, mapowania kategorii oraz żywe odczyty z konektora (produkty, kategorie, parametry, podmioty GPSR). Żywe odczyty są płatne (liczą się do limitu API konektora), ale tylko do odczytu. |
| offers:write | Zapis ofert marketplace: mapowania kategorii (tworzenie, zbiorcze, przekierowanie, usuwanie, synchronizacja cache) oraz publikacja, synchronizacja, pull, odświeżanie statusu i import realnych ofert. Publikacja i sync są płatne (realne wywołanie do marketplace). |
| reports:read | Raporty sprzedaży, produktów i operacji + eksport CSV/XLSX. Dane wrażliwe biznesowo. |
| analytics:read | Analityka AI: prognozy zapasów, sugestie cen, anomalie, prognoza sprzedaży, wnioski. |
| monitoring:read | Monitoring integracji (webhooki, faktury, kolejka błędów) i zużycie konta. Detale zawierają dane osobowe. |
| monitoring:write | Ponowne przetwarzanie wpisu z kolejki błędów - odpala oryginalny proces (dla faktur wystawia realną fakturę; płatne). |
| customers:read | Klienci (agregacja z zamówień), statystyki, historia i eksport CSV. Pełne dane osobowe. |
| email:read | Szablony i logi e-mail. Logi zawierają adresy odbiorców i tematy. |
| email:write | Zapis szablonów e-mail (limit planu) oraz wysyłka wiadomości (płatna u dostawcy; dedykowany limit ~10/godz). |
| notifications:read | Powiadomienia w aplikacji i preferencje. |
| notifications:write | Tworzenie powiadomień w aplikacji (odbiorca musi być członkiem konta) i oznaczanie jako przeczytane. |
| alerts:read | Reguły alertów i historia wyzwoleń. |
| alerts:write | Zapis reguł alertów (kanał e-mail pośrednio generuje wysyłki). |
| postsale:read | Obsługa posprzedażowa: wiadomości, spory, zwroty, roszczenia (tylko odczyt). Dane osobowe kupujących. |
| postsale:write | Zapis posprzedaży bez ruchu środków: odpowiedzi w wątkach i sporach, decyzja w sporze, akceptacja/odrzucenie zwrotu (capability-gated per konektor). |
| postsale:refunds:write | Odrębny zakres pieniężny: realny zwrot środków kupującemu i zwrot prowizji. Wydzielony, aby wyciekły klucz bez niego nie ruszył pieniędzy. |
| templates:read | Odczyt szablonów opisów i szablonów produktów (z wariantami). |
| templates:write | Zapis szablonów opisów i produktów; zastosowanie szablonu tworzy produkt (wymaga też catalog:write). |
| ai:read | Odczyt ustawień AI i historii generowania treści. |
| ai:write | Generowanie i tłumaczenie treści przez AI (płatne u Twojego dostawcy). Zapis do produktu wymaga też catalog:write. |
Limity per plan
Limity są agregowane per konto (nie per klucz). Nagłówki X-RateLimit-Limit, X-RateLimit-Remaining i X-RateLimit-Reset na każdej odpowiedzi informują o stanie okna. Po przekroczeniu limitu otrzymasz 429 z nagłówkiem Retry-After.
| Plan | Klucze API | Zapytania | Webhooki |
|---|---|---|---|
| Basic | 5 | 1000 / min | 15 |
| Professional | 30 | 3000 / min | 50 |
| Enterprise | Bez limitu | Bez limitu | Bez limitu |
Zasoby i operacje
Odczyt (paginacja kursorowa, filtry, sortowanie):
GET /orders GET /orders/{id} GET /orders/stats
GET /orders/{id}/status-history
GET /warehouse-items GET /warehouse-items/{id}
GET /invoices GET /invoices/{id} GET /invoices/stats
GET /shipments GET /shipments/{id} GET /shipments/statsZapis:
PUT /orders/{id}/status # change the status (transition matrix)
POST /orders # create an order (source: api)
POST /orders/{id}/invoice # trigger invoicing
PATCH /warehouse-items/{id}/stock # stock correction (set / adjust)Przykład - lista ostatnich zamówień:
curl "https://{your-slug}.navyflame.com/api/public/v1/orders?limit=25" \
-H "Authorization: Bearer nf_live_your_key"Przykład - korekta stanu magazynowego o -3 sztuki (atomowo):
curl -X PATCH \
"https://{your-slug}.navyflame.com/api/public/v1/warehouse-items/{id}/stock" \
-H "Authorization: Bearer nf_live_your_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f9a...-unikat" \
-d '{"operation":"adjust","quantity":-3}'Analityka, raporty i monitoring
Read-only zasoby analityczne (zakresy reports:read, analytics:read, monitoring:read). Kwoty w raportach i analityce to liczby (agregaty), w odróżnieniu od zasobów transakcyjnych, gdzie kwoty są tekstem z dwoma miejscami po przecinku.
GET /reports/sales GET /reports/sales/channels
GET /reports/sales/countries GET /reports/products/bestsellers
GET /reports/products/high-returns GET /reports/products/low-rotation
GET /reports/operations/sla GET /reports/operations/fulfillment
GET /reports/export/csv GET /reports/export/xlsx # binary files
GET /ai-ops/status GET /ai-ops/stock-predictions
GET /ai-ops/price-optimizations GET /ai-ops/anomalies
GET /ai-ops/sales-forecast GET /ai-ops/insights # billable (LLM)
GET /monitoring/webhooks GET /monitoring/webhooks/{id}
GET /monitoring/invoice-links GET /monitoring/dlq
GET /monitoring/dlq/{id} GET /monitoring/stats
GET /usage # counters, storage used, plan limitsEksporty /reports/export/csv i /xlsx to wyjątek binarny od formatu JSON - zwracają plik z nagłówkiem Content-Disposition: attachment (CSV w UTF-8 z BOM, separator średnik). Błędy nadal zwracamy jako application/problem+json.
Detale /monitoring/webhooks/{id} i /monitoring/dlq/{id} zawierają surowy payload konektora (dane osobowe kupującego) - zakres monitoring:read jest oznaczony jako wrażliwy. Listy tych zasobów payloadu nie zwracają.
Przykład - podsumowanie sprzedaży z ostatnich 30 dni:
curl "https://{your-slug}.navyflame.com/api/public/v1/reports/sales?periodDays=30" \
-H "Authorization: Bearer nf_live_your_key"Klienci, e-maile, powiadomienia i obsługa posprzedażowa
Zasoby zawierające dane osobowe (zakresy customers:read, email:read, notifications:read, alerts:read, postsale:read). Tylko odczyt.
GET /customers GET /customers/{email}
GET /customers/stats GET /customers/{email}/orders
GET /customers/growth GET /customers/export # CSV
GET /email-templates(/{id}) GET /email-logs
GET /notifications(/{id}) GET /notifications/unread-count
GET /notification-preferences # needs ?userId=
GET /alert-rules(/{id}) GET /alert-rules/history
GET /post-sale/capabilities GET /post-sale/inbox
GET /post-sale/conversations(/{id})(/messages)
GET /post-sale/disputes(/{id})(/messages)
GET /post-sale/returns(/{id}) GET /post-sale/refundsKlient to byt wirtualny (agregacja z zamówień), adresowany adresem e-mail. Powiadomienia są tenant-wide (klucz API nie reprezentuje jednego użytkownika); opcjonalny ?userId= zawęża do odbiorcy, a preferencje go wymagają. Obsługa posprzedażowa czyta wyłącznie dane zapisane w systemie (bez wywołań do marketplace na Twój koszt); dostępność sprawdzisz w /post-sale/capabilities.
Zakresy customers:read, email:read i postsale:read udostępniają dane osobowe - nadawaj je tylko zaufanym integracjom i przetwarzaj zgodnie z RODO.
Katalog, szablony i AI
Pełny zapis katalogu (zakresy catalog:read / catalog:write). Operacje tworzące i nieodwracalne wymagają nagłówka Idempotency-Key - ponowienie z tym samym kluczem odtwarza zapisany wynik zamiast wykonać operację raz jeszcze.
# Products
POST/PUT/DELETE /warehouse-items(/{id}) POST /warehouse-items/{id}/backorder
GET /warehouse-items/by-barcode GET /warehouse-items/{id}/stock-history
# Warehouses and locations
GET/POST/PUT/DELETE /warehouses(/{id})
GET /warehouse-items/{id}/locations PUT /warehouse-items/{id}/locations/{warehouseId}
GET/PUT /warehouse-settings
# Reservations and stock documents
GET/POST /reservations DELETE /reservations/{id}
GET/POST /stock-documents(/{id}) POST /stock-documents/{id}/lines
POST /stock-documents/{id}/commit POST /stock-documents/{id}/cancel
# Bundles
GET /bundles(/{id}) PUT /bundles/{id} DELETE /bundles/{id}Szablony opisów i produktów (zakresy templates:read / templates:write). Zastosowanie szablonu tworzy produkt, więc POST /product-templates/{id}/apply wymaga dodatkowo catalog:write.
GET/POST/PUT/DELETE /description-templates(/{id})
GET/POST/PUT/DELETE /product-templates(/{id})
PUT /product-templates/{id}/variants # replace the whole set of variants
POST /product-templates/{id}/variants # add a variant
PATCH/DELETE /product-templates/{id}/variants/{variantId}
POST /product-templates/{id}/apply # + catalog:writeTreści AI (zakresy ai:read / ai:write). Generowanie i tłumaczenie to operacje płatne u Twojego dostawcy AI (klucz konfigurujesz w integracjach), dlatego Idempotency-Key jest wymagany - ponowienie odtwarza wynik, nie nalicza go ponownie. Zapis wyniku do produktu (applyToProduct / createNewProducts) wymaga dodatkowo catalog:write. Operacje wsadowe zwracają skrócony podgląd na pozycję - pełny tekst pobierzesz z /ai/generation-logs lub z produktu.
GET/PUT /ai/settings GET /ai/generation-logs
POST /ai/generate-description POST /ai/translate
POST /ai/batch-generate POST /ai/batch-translate # up to 50 items
POST /ai/preview-template # no AI; templates:read + catalog:readPrzykład - utworzenie szablonu opisu (idempotentnie):
curl -X POST \
"https://{your-slug}.navyflame.com/api/public/v1/description-templates" \
-H "Authorization: Bearer nf_live_your_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f1e-tpl-001" \
-d '{"name":"Premium description","templateBody":"{{productName}} - {{price}} {{currency}}"}'Konfiguracja wysyłki
Konfiguracja wysyłki (zakresy shipping:read / shipping:write): reguły wysyłki, strefy ze stawkami, opcje dostawy i nadpisania per produkt, plus kalkulator kosztów. Operacje tworzące wymagają nagłówka Idempotency-Key. Kwoty i wagę w zapisie przekazujesz jako liczby (nie tekst). To konfiguracja, a nie obsługa kuriera - nadawanie przesyłek i etykiety pojawią się w osobnej fazie.
# Shipping rules
GET/POST/PUT/DELETE /shipping-rules(/{id})
# Zones and rates (a rate belongs to its owning zone)
GET/POST/PUT/DELETE /shipping-zones(/{id})
POST /shipping-zones/{id}/rates PUT/DELETE /shipping-zones/{id}/rates/{rateId}
# Delivery options
GET/POST/PUT/DELETE /delivery-options(/{id})
# Per-product shipping overrides
GET/POST /products/{productId}/shipping-overrides
PUT/DELETE /product-shipping-overrides/{id}
# Cost calculator (a POST, but it only needs shipping:read)
POST /shipping/calculateNazwy nie są unikalne, więc nie ma konfliktu duplikatu (409). deliveryOptionId w stawce i nadpisaniu musi wskazywać Twoją opcję dostawy (inaczej 422), a stawka spoza Twojej strefy zwraca 404. Kalkulator zwraca listę opcji posortowaną rosnąco po koszcie.
Przykład - wyliczenie kosztów wysyłki do Polski:
curl -X POST \
"https://{your-slug}.navyflame.com/api/public/v1/shipping/calculate" \
-H "Authorization: Bearer nf_live_your_key" \
-H "Content-Type: application/json" \
-d '{"countryCode":"PL","orderValue":199.99,"totalWeightKg":1.5,"itemCount":2}'Przesyłki, etykiety i kurier
Lifecycle przesyłek (zakres shipments:write) oraz odczyty pomocnicze kuriera (zakres shipments:read): tworzysz przesyłkę, zamawiasz etykietę u przewoźnika, anulujesz, odświeżasz tracking i przekazujesz numer śledzenia do Allegro. Wagę, wymiary i kwoty przekazujesz jako liczby.
# Creating a shipment (status Draft; costs nothing)
POST /shipments # one at a time
POST /shipments/bulk # in bulk, up to 100 (partial success)
# The carrier label
POST /shipments/{id}/label # BILLABLE - buying a label (Idempotency-Key required)
GET /shipments/{id}/label # fetch the label (PDF, binary)
# The rest of the lifecycle
DELETE /shipments/{id} # delete a draft or cancel with the carrier
POST /shipments/{id}/refresh-tracking
POST /shipments/{id}/push-tracking
# Helper reads (shipments:read)
GET /shipments/points # pickup points (InPost, Poczta Polska, Furgonetka)
GET /couriers/{provider}/services # carrier services (Apaczka, Furgonetka)
GET /shipments/allegro/delivery-services # Allegro Delivery services
POST /shipments/available-dates # pickup dates (DHL; a POST, but shipments:read)Zamówienie etykiety jest płatne - kupuje realną przesyłkę u przewoźnika. Dlatego POST /shipments/{id}/label wymaga nagłówka Idempotency-Key: ponowienie z tym samym kluczem odtwarza zapisany wynik i nigdy nie kupuje etykiety drugi raz (zabezpieczenie działa po stronie serwera). Etykietę zamówisz tylko dla przesyłki w statusie Szkic. Pobranie etykiety (GET .../label) to wyjątek binarny - zwraca application/pdf, a nie JSON.
Konektor kuriera lub Allegro, który nie jest połączony, zwraca 403 not_supported (nigdy 500), a błąd po stronie przewoźnika lub Allegro - 502 bad_gateway. Odczyty pomocnicze dla nieobsługiwanego dostawcy zwracają { "supported": false } zamiast błędu. Anulowanie nie zmienia statusu lokalnego, jeśli przewoźnik odrzuci operację.
Przykład - zamówienie etykiety (idempotentnie, płatne):
curl -X POST \
"https://{your-slug}.navyflame.com/api/public/v1/shipments/{id}/label" \
-H "Authorization: Bearer nf_live_your_key" \
-H "Idempotency-Key: 6f9a...-label-001"Konektory i oferty marketplace
Odkrywanie konektorów (zakres integrations:read) oraz odczyty i zapisy ofert marketplace (zakresy offers:read / offers:write). Część operacji jest lokalna (z Twoich danych, bez kosztów), a część to żywe, płatne wywołania do konektora - oznaczone niżej.
Odkrywanie i lokalne odczyty (bez kosztów):
GET /connectors # the list of connectors (no secrets)
GET /warehouse-items/{id}/listings # the product's marketplace offers (keyset)
GET /category-mappings # category mappings (keyset)GET /connectors zwraca ściśle ograniczony zestaw pól - key, configId, displayName, enabled i connected - i nigdy nie zwraca danych logowania (kluczy API, tokenów ani haseł konektora). Pole connected to wyliczony status: konektor jest włączony i ma zapisane poświadczenia. Wartość configId przekażesz jako filtr ?sourceConfigId= lub ?destConfigId= w mapowaniach kategorii.
Oferty produktu (/warehouse-items/{id}/listings) wiążą pozycję magazynową z ofertą w kanale (zewnętrzne ID, cena i status po stronie marketplace, ewentualne nadpisanie ceny per kanał). Każdy obiekt oferty zawiera instanceId, czyli trwałe ID konkretnego połączenia, oraz instanceName do wyświetlenia użytkownikowi. Dzięki temu ten sam produkt może mieć niezależne oferty, ceny i stan synchronizacji na przykład na ebay.de i ebay.com. Pole lastSyncError jest oczyszczane z wzorców poświadczeń, które błąd konektora mógłby zawierać.
Przykład - lista konektorów konta:
curl "https://{your-slug}.navyflame.com/api/public/v1/connectors" \
-H "Authorization: Bearer nf_live_your_key"Żywe odczyty marketplace (zakres offers:read) wykonują realne wywołanie do konektora - są płatne (liczą się do limitu API konektora), ale wyłącznie do odczytu (nie publikują ani nie zmieniają oferty). Konektor niepołączony zwraca 403 not_supported (nigdy 500), błąd po stronie marketplace - 502 bad_gateway. Kształt danych zależy od konektora.
GET /marketplace/{connectorKey}/products
GET /marketplace/{connectorKey}/products/{externalProductId}
GET /marketplace/{connectorKey}/categories?q=fraza
GET /marketplace/{connectorKey}/categories/{categoryId}/parameters
GET /marketplace/{connectorKey}/responsible-producers
GET /marketplace/{connectorKey}/responsible-personsZapis mapowań kategorii (zakres offers:write) to zapisy lokalne - żadne z nich nie publikuje ani nie zmienia realnej oferty widocznej dla kupującego (publikację realnej oferty opisano niżej). POST /category-mappings wymaga nagłówka Idempotency-Key (duplikat -> 409); sync odświeża lokalny cache kategorii z konektora (płatne, ale idempotentne).
POST /category-mappings # create (Idempotency-Key required; a duplicate -> 409)
POST /category-mappings/bulk # in bulk (up to 1000; duplicates skipped)
PUT /category-mappings/{id} # repoint the mapping at another target
DELETE /category-mappings/{id} # delete the mapping
POST /category-mappings/sync # refresh the local category cache (billable, idempotent)Publikacja i synchronizacja realnych ofert (zakres offers:write) tworzy lub aktualizuje ofertę widoczną dla kupującego w kanale - operacje płatne (realne wywołanie do marketplace). publish i sync wymagają nagłówka Idempotency-Key (retry z tym samym kluczem odtwarza zapisaną odpowiedź zamiast ponawiać płatne wywołanie). publish zwraca 409, gdy produkt jest już opublikowany na tym konkretnym połączeniu (lub jego publikacja jest w toku) - oferta na innej instancji tego samego konektora nie powoduje konfliktu. Wtedy użyj sync dla tego samego configId. Konektor niepołączony -> 403 not_supported, błąd po stronie marketplace -> 502 bad_gateway.
W body operacji publish, sync i PUT .../pricing przekaż configId otrzymane z GET /connectors. Jeśli konektor ma kilka włączonych połączeń, pominięcie pola kończy się 422 validation_failed. API nie wybiera konta domyślnego w ciemno. Gdy istnieje dokładnie jedno włączone połączenie, może je rozstrzygnąć automatycznie.
Ważne przy błędzie 502 na publikacji: timeout lub błąd 5xx marketplace jest niejednoznaczny - oferta mogła powstać. Retry z tym samym Idempotency-Key odtworzy to samo 502 (nie opublikuje ponownie). Zweryfikuj ofertę w kanale i ponów z nowym Idempotency-Key dopiero wtedy, gdy wiesz, że oferta nie powstała.
POST /warehouse-items/{id}/publish/{connectorKey} # publish the offer (billable; Idempotency-Key required)
POST /warehouse-items/{id}/sync/{connectorKey} # update the offer (billable; Idempotency-Key required)
POST /warehouse-items/{id}/pull/{connectorKey} # pull the offer from the channel into the catalogue
POST /warehouse-items/{id}/refresh-status/{connectorKey} # refresh the status of one offer
POST /warehouse-items/refresh-status # in bulk (up to 100 products)
PUT /warehouse-items/{id}/listings/{connectorKey}/pricing # price per instance (local, no outbound call)
# Body for publish / sync:
{ "configId": "8d1ec28d-..." }
# Body for pricing:
{ "configId": "8d1ec28d-...", "mode": "markup", "value": 12.5 }Import oferty do magazynu ( POST /catalog/import) tworzy pozycję magazynową z produktu marketplace. Wymaga dwóch zakresów naraz - offers:write oraz catalog:write (brak jednego -> 403 missing_scope) - i nagłówka Idempotency-Key. Duplikat SKU lub kodu kreskowego -> 409 conflict.
POST /catalog/import # import a marketplace product -> a stock item (offers:write + catalog:write)Zapis: powiadomienia, alerty, e-mail i obsługa posprzedażowa
Zapis komunikacji, ponownego przetwarzania i obsługi posprzedażowej (zakresy notifications:write, alerts:write, email:write, monitoring:write, postsale:write i postsale:refunds:write). Operacje tworzące i nieodwracalne wymagają nagłówka Idempotency-Key; operacje naturalnie idempotentne (oznaczanie jako przeczytane, toggle) honorują go opcjonalnie.
# Notifications (notifications:write)
POST /notifications # create (the recipient must be a member of the account; Idempotency-Key required)
POST /notifications/{id}/read # mark one as read
POST /notifications/read-all # mark all (needs ?userId=)
# Alerts (alerts:write)
POST /alert-rules # create a rule (Idempotency-Key required)
PUT/DELETE /alert-rules/{id} # update / delete
POST /alert-rules/{id}/toggle # enable / disable
# E-mail (email:write)
POST/PUT/DELETE /email-templates(/{id}) # templates (plan limit; a duplicate name -> 409)
POST /emails/send # BILLABLE - a real send (Idempotency-Key required)Tworzenie powiadomienia sprawdza, czy recipientUserId jest członkiem konta (nie-członek -> 422, niepewna weryfikacja -> 503) - klucz API nie może zasypać skrzynki dowolnego użytkownika. Szablony e-mail podlegają limitowi planu (Basic 10, Professional 24, Enterprise bez limitu) -> 403 plan_limit, a duplikat nazwy -> 409. Wysyłka e-mail (`POST /emails/send`) jest płatna i objęta dedykowanym limitem ~10 na godzinę per konto ( 429); dostawca bez konfiguracji -> 403 not_supported, błąd transportu -> 502 bad_gateway. Reguła alertu z kanałem email lub both pośrednio generuje wysyłki przy wyzwoleniu.
Ponowne przetwarzanie kolejki błędów (zakres monitoring:write) odpala oryginalny proces wpisu DLQ - dla źródeł fakturowania wystawia realną fakturę, więc jest płatne i destrukcyjne, a Idempotency-Key jest wymagany. Retriable są tylko trzy źródła (shopify_to_wfirma_pipeline, shopify, wfirma_invoice) - inne zwracają 422; niedostępny Temporal -> 503. Powtórzenie jest idempotentne po deterministycznym identyfikatorze procesu (zwraca alreadyRunning).
POST /monitoring/dlq/{id}/retry # BILLABLE - runs the original process (Idempotency-Key required)Obsługa posprzedażowa (zakres postsale:write): odpowiadasz w wątkach i sporach, zmieniasz status sporu, akceptujesz lub odrzucasz zwrot. Własność wątku, sporu lub zwrotu jest sprawdzana przed wywołaniem kanału (cudzy lub nieistniejący identyfikator -> 404), a operacje są capability-gated per konektor - brak danej zdolności lub metody zwraca 403 not_supported (nigdy 500). Błąd kanału -> 502 bad_gateway.
# Post-sale handling with no movement of money (postsale:write)
POST /post-sale/conversations/{id}/messages # reply to the buyer (Idempotency-Key required)
POST /post-sale/conversations/{id}/read # mark the thread read
POST /post-sale/disputes/{id}/messages # reply in a dispute (Idempotency-Key required)
POST /post-sale/disputes/{id}/status # a decision in a dispute (see money isolation)
POST /post-sale/returns/{id}/accept # accept the return
POST /post-sale/returns/{id}/reject # reject the return
# Refunds - a SEPARATE money scope (postsale:refunds:write)
POST /post-sale/refunds/issue # a REAL refund to the buyer
POST /post-sale/refunds/commission-claim # a commission refundIzolacja pieniędzy. Zwrot środków ma odrębny zakres `postsale:refunds:write`, wydzielony od postsale:write, tak aby wyciekły klucz bez tego zakresu nie mógł ruszyć pieniędzy. Trasa POST /post-sale/disputes/{id}/status należy do postsale:write, ale jeśli decyzja przenosi środki do kupującego (obecne partialRefund albo status ACCEPTED_REFUND / ACCEPTED_PARTIAL_REFUND), klucz musi dodatkowo nieść `postsale:refunds:write` - inaczej żądanie zwraca 403 missing_scope i nic się nie wykonuje.
Ponawianie zwrotów. refunds/issue i commission-claim są idempotentne po stronie kanału (Twój Idempotency-Key staje się identyfikatorem operacji na kanale) - na 502 ponów z tym samym kluczem, a kanał zdeduplikuje. Natomiast decyzja sporu przenosząca środki nie ma idempotencji po stronie kanału - na niepewny błąd zweryfikuj wynik w kanale sprzedaży i ponów dopiero z nowym Idempotency-Key (to samo 502 jest zwracane dla tego samego klucza).
Przykład - realny zwrot środków (idempotentnie, płatne):
curl -X POST \
"https://{your-slug}.navyflame.com/api/public/v1/post-sale/refunds/issue" \
-H "Authorization: Bearer nf_live_your_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 6f9a...-refund-001" \
-d '{"connectorKey":"shopify","instanceId":"shop-1","orderExternalId":"1234","amount":49.99,"currency":"PLN"}'Pełny wykaz operacji (per zasób)
Kompletny, nawigowalny indeks wszystkich publicznych endpointów v1 pogrupowanych per zasób. To jest warstwa dla człowieka - pełne, polowe schematy żądań i odpowiedzi (179 schematów) znajdziesz w specyfikacji OpenAPI . Każdy żyjący endpoint jest tu wymieniony.
- Zakres - wymagany zakres klucza. Zakres
:writeobejmuje odpowiadający mu:read. Zapisa + boznacza cross-scope (potrzebne oba naraz). - Idem. -
K!= nagłówekIdempotency-Keywymagany;K?= honorowany (opcjonalny); puste = nie dotyczy (odczyt). - Błędy - kluczowe kody poza uniwersalnymi
401,403,429(oraz500/503, które mogą wystąpić wszędzie).
Meta
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /me | (brak) | - | Introspekcja klucza: plan, limity, zakresy. Nie wymaga zakresu. | - |
Zamówienia
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /orders | orders:read | - | Lista zamówień (keyset; filtry status / źródło / data / szukaj). | 422 |
POST /orders | orders:write | K! | Utwórz zamówienie (source=api); kwoty liczy serwer. | 409,413,415,422 |
GET /orders/{id} | orders:read | - | Szczegóły zamówienia. | 404 |
PUT /orders/{id}/status | orders:write | K? | Zmień status (macierz przejść; writeback do Allegro). | 404,415,422 |
POST /orders/{id}/invoice | orders:write | K! | Wyzwól fakturowanie (asynchroniczne). | 404,409,422 |
GET /orders/stats | orders:read | - | Statystyki zamówień (liczniki per status + przychód Paid). | 422 |
GET /orders/{id}/status-history | orders:read | - | Historia realnych przejść statusu zamówienia. | 404,422 |
Katalog - produkty
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /warehouse-items | catalog:read | - | Lista produktów (keyset; filtr status / sku / barcode). | 422 |
POST /warehouse-items | catalog:write | K! | Utwórz produkt magazynowy. | 409,413,415,422 |
GET /warehouse-items/{id} | catalog:read | - | Szczegóły produktu (z wariantami). | 404 |
PUT /warehouse-items/{id} | catalog:write | K! | Zaktualizuj produkt. | 404,409,413,415,422 |
DELETE /warehouse-items/{id} | catalog:write | K! | Zarchiwizuj produkt (miękkie usunięcie). | 404,409,422 |
PATCH /warehouse-items/{id}/stock | catalog:write | K? | Ustaw / skoryguj stan (set / adjust, atomowo). | 404,415,422 |
GET /warehouse-items/by-barcode | catalog:read | - | Znajdź produkt lub wariant po kodzie kreskowym. | 404,422 |
GET /warehouse-items/{id}/stock-history | catalog:read | - | Historia zmian stanu produktu (keyset). | 404,422 |
POST /warehouse-items/{id}/backorder | catalog:write | K! | Włącz / wyłącz backorder produktu. | 404,409,415,422 |
Katalog - magazyny i lokalizacje
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /warehouses | catalog:read | - | Lista magazynów / lokalizacji. | - |
POST /warehouses | catalog:write | K! | Utwórz magazyn / lokalizację. | 409,415,422 |
PUT /warehouses/{id} | catalog:write | K! | Zaktualizuj magazyn. | 404,409,415,422 |
DELETE /warehouses/{id} | catalog:write | K! | Usuń magazyn. | 404,409,422 |
GET /warehouse-items/{id}/locations | catalog:read | - | Stan produktu w rozbiciu na lokalizacje. | 404 |
PUT /warehouse-items/{id}/locations/{warehouseId} | catalog:write | K! | Ustaw stan produktu w danej lokalizacji. | 404,409,415,422 |
GET /warehouse-settings | catalog:read | - | Ustawienia automatyzacji magazynu. | - |
PUT /warehouse-settings | catalog:write | K? | Zmień ustawienia automatyzacji magazynu, w tym tryb synchronizacji stanów. | 409,415,422 |
Katalog - rezerwacje i dokumenty magazynowe
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /reservations | catalog:read | - | Lista rezerwacji stanu (keyset). | 422 |
POST /reservations | catalog:write | K! | Zarezerwuj stan produktu. | 404,409,415,422 |
DELETE /reservations/{id} | catalog:write | K! | Zwolnij rezerwację. | 404,409 |
GET /stock-documents | catalog:read | - | Lista dokumentów magazynowych (keyset). | 422 |
POST /stock-documents | catalog:write | K! | Utwórz dokument magazynowy (szkic). | 409,415,422 |
GET /stock-documents/{id} | catalog:read | - | Szczegóły dokumentu (z pozycjami). | 404 |
POST /stock-documents/{id}/lines | catalog:write | K! | Dodaj pozycję do dokumentu. | 404,409,415,422 |
DELETE /stock-documents/{id}/lines/{lineId} | catalog:write | K! | Usuń pozycję z dokumentu. | 404,409,422 |
POST /stock-documents/{id}/commit | catalog:write | K! | Zatwierdź dokument (zastosuj stan). | 404,409,422 |
POST /stock-documents/{id}/cancel | catalog:write | K! | Anuluj dokument magazynowy. | 404,409,422 |
Katalog - zestawy i cenniki
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /bundles | catalog:read | - | Lista zestawów (keyset). | 422 |
GET /bundles/{id} | catalog:read | - | Szczegóły zestawu (komponenty + stan wyliczony). | 404 |
PUT /bundles/{id} | catalog:write | K! | Ustaw komponenty zestawu. | 404,409,415,422 |
DELETE /bundles/{id} | catalog:write | K! | Usuń zestaw (wyczyść komponenty). | 404,409,422 |
GET /price-lists | catalog:read | - | Lista cenników z UUID potrzebnym do odczytu lub zapisu ceny. | - |
GET /price-list-entries | catalog:read | - | Odczytaj zapisaną cenę i walutę po priceListId (UUID) i sku. Brak ceny lub SKU: 404. Błędne parametry: 400. Odczyt przed PUT nie gwarantuje atomowego audytu. | 400,404 |
PUT /price-list-entries | catalog:write | K? | Ustaw cenę pozycji po sku oraz priceListId lub name. GET przed i po PUT pozwala porównać poprzednią i zapisaną cenę. | 404,409,415,422 |
Szablony (opisów i produktów)
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /description-templates | templates:read | - | Lista szablonów opisów (keyset). | 422 |
POST /description-templates | templates:write | K! | Utwórz szablon opisu. | 409,413,415,422 |
GET /description-templates/{id} | templates:read | - | Szczegóły szablonu opisu. | 404 |
PUT /description-templates/{id} | templates:write | K? | Zaktualizuj szablon opisu. | 404,409,413,415,422 |
DELETE /description-templates/{id} | templates:write | K? | Usuń szablon opisu. | 404 |
GET /product-templates | templates:read | - | Lista szablonów produktów (keyset). | 422 |
POST /product-templates | templates:write | K! | Utwórz szablon produktu. | 409,413,415,422 |
GET /product-templates/{id} | templates:read | - | Szczegóły szablonu produktu (z wariantami). | 404 |
PUT /product-templates/{id} | templates:write | K? | Zaktualizuj szablon produktu. | 404,409,413,415,422 |
DELETE /product-templates/{id} | templates:write | K? | Usuń szablon produktu. | 404 |
PUT /product-templates/{id}/variants | templates:write | K? | Zamień komplet wariantów szablonu (bulk). | 404,409,413,415,422 |
POST /product-templates/{id}/variants | templates:write | K! | Dodaj wariant do szablonu. | 404,409,415,422 |
PATCH /product-templates/{id}/variants/{variantId} | templates:write | K? | Zaktualizuj wariant szablonu. | 404,409,415,422 |
DELETE /product-templates/{id}/variants/{variantId} | templates:write | K? | Usuń wariant szablonu. | 404 |
POST /product-templates/{id}/apply | templates:write + catalog:write | K! | Utwórz produkt z szablonu (cross-scope). | 404,409,422 |
AI - generowanie treści
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /ai/settings | ai:read | - | Globalne ustawienia generowania AI. | - |
PUT /ai/settings | ai:write | K? | Zmień globalne ustawienia AI. | 409,415,422 |
GET /ai/generation-logs | ai:read | - | Historia wywołań AI (keyset). | 422 |
POST /ai/generate-description | ai:write | K! | Wygeneruj opis produktu (billable). | 404,409,415,422 |
POST /ai/translate | ai:write | K! | Przetłumacz produkt (billable). | 404,409,415,422 |
POST /ai/batch-generate | ai:write | K! | Wygeneruj opisy wsadowo (billable; max 50). | 409,413,415,422 |
POST /ai/batch-translate | ai:write | K! | Przetłumacz wsadowo (billable; max 50). | 409,413,415,422 |
POST /ai/preview-template | templates:read + catalog:read | - | Podgląd szablonu z danymi produktu (bez LLM; cross-scope). | 404,413,415,422 |
Analityka AI (AI-Ops)
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /ai-ops/status | analytics:read | - | Status konfiguracji AI + pokrycie danymi. | - |
GET /ai-ops/stock-predictions | analytics:read | - | Prognoza wyczerpania zapasów per SKU (cache 5 min). | 422 |
GET /ai-ops/price-optimizations | analytics:read | - | Sugestie cenowe z historii zmian cen (cache 5 min). | 422 |
GET /ai-ops/anomalies | analytics:read | - | Anomalie vs średnia krocząca (cache 5 min). | 422 |
GET /ai-ops/sales-forecast | analytics:read | - | Prognoza sprzedaży (regresja; days = horyzont). | 422 |
GET /ai-ops/insights | analytics:read | - | Wnioski (billable LLM tenanta; cache 30 min; fallback regułowy). | - |
Faktury
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /invoices | invoices:read | - | Lista faktur (keyset; issueDate desc). | 422 |
GET /invoices/{id} | invoices:read | - | Szczegóły faktury (z pozycjami i KSeF). | 404 |
GET /invoices/stats | invoices:read | - | Statystyki faktur (KPI lifetime). | - |
Przesyłki i kurier
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /shipments | shipments:read | - | Lista przesyłek (keyset). | 422 |
GET /shipments/{id} | shipments:read | - | Szczegóły przesyłki (z historią trackingu). | 404 |
GET /shipments/stats | shipments:read | - | Statystyki przesyłek (liczniki per status). | - |
POST /shipments | shipments:write | K! | Utwórz przesyłkę (status Szkic; bez kosztu). | 409,415,422 |
POST /shipments/bulk | shipments:write | K! | Utwórz przesyłki zbiorczo (max 100, partial success). | 409,413,415,422 |
POST /shipments/{id}/label | shipments:write | K! | Zamów etykietę kurierską (billable - realny koszt). | 404,409 |
GET /shipments/{id}/label | shipments:read | - | Pobierz etykietę kurierską (PDF, binarny). | 404,409,502 |
DELETE /shipments/{id} | shipments:write | K! | Usuń niewysłany szkic lub anuluj przesyłkę u kuriera. | 404,409,502 |
POST /shipments/{id}/refresh-tracking | shipments:write | K? | Odśwież status i tracking u kuriera. | 404,409,502 |
POST /shipments/{id}/push-tracking | shipments:write | K! | Wyślij numer śledzenia do zamówienia w marketplace, z którego pochodzi (Allegro, TikTok Shop). | 404,400,502 |
POST /shipments/{id}/push-to-allegro | shipments:write | K! | To samo, ale wyłącznie dla Allegro. Zachowane dla zgodności wstecznej - w nowych integracjach używaj push-tracking. | 404,409,422,502 |
POST /shipments/available-dates | shipments:read | - | Dostępne terminy nadania (DHL; POST-but-read). | 415,422,502 |
GET /shipments/points | shipments:read | - | Punkty odbioru / paczkomaty (InPost, Poczta Polska, Furgonetka; parametr service zawęża wyniki Furgonetki do przewoźnika usługi). | 502 |
GET /couriers/{provider}/services | shipments:read | - | Lista usług kuriera (Apaczka, Furgonetka). | 502 |
GET /shipments/allegro/delivery-services | shipments:read | - | Lista usług Allegro Delivery. | 502 |
Konfiguracja wysyłki
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /shipping-rules | shipping:read | - | Lista reguł wysyłki (keyset). | 422 |
POST /shipping-rules | shipping:write | K! | Utwórz regułę wysyłki. | 409,415,422 |
GET /shipping-rules/{id} | shipping:read | - | Szczegóły reguły wysyłki. | 404 |
PUT /shipping-rules/{id} | shipping:write | K? | Zaktualizuj regułę wysyłki. | 404,409,415,422 |
DELETE /shipping-rules/{id} | shipping:write | K? | Usuń regułę wysyłki. | 404 |
GET /shipping-zones | shipping:read | - | Lista stref wysyłki (z zagnieżdżonymi stawkami). | 422 |
POST /shipping-zones | shipping:write | K! | Utwórz strefę wysyłki. | 409,415,422 |
GET /shipping-zones/{id} | shipping:read | - | Szczegóły strefy (z zagnieżdżonymi stawkami). | 404 |
PUT /shipping-zones/{id} | shipping:write | K? | Zaktualizuj strefę wysyłki. | 404,409,415,422 |
DELETE /shipping-zones/{id} | shipping:write | K? | Usuń strefę wysyłki. | 404 |
POST /shipping-zones/{id}/rates | shipping:write | K! | Dodaj stawkę do strefy. | 404,409,415,422 |
PUT /shipping-zones/{id}/rates/{rateId} | shipping:write | K? | Zaktualizuj stawkę w strefie. | 404,409,415,422 |
DELETE /shipping-zones/{id}/rates/{rateId} | shipping:write | K? | Usuń stawkę ze strefy. | 404 |
GET /delivery-options | shipping:read | - | Lista opcji dostawy (keyset). | 422 |
POST /delivery-options | shipping:write | K! | Utwórz opcję dostawy. | 409,415,422 |
GET /delivery-options/{id} | shipping:read | - | Szczegóły opcji dostawy. | 404 |
PUT /delivery-options/{id} | shipping:write | K? | Zaktualizuj opcję dostawy. | 404,409,415,422 |
DELETE /delivery-options/{id} | shipping:write | K? | Usuń opcję dostawy. | 404 |
GET /products/{productId}/shipping-overrides | shipping:read | - | Nadpisania wysyłki dla produktu (keyset). | 404,422 |
POST /products/{productId}/shipping-overrides | shipping:write | K! | Utwórz nadpisanie wysyłki dla produktu. | 404,409,415,422 |
PUT /product-shipping-overrides/{id} | shipping:write | K? | Zaktualizuj nadpisanie wysyłki produktu. | 404,409,415,422 |
DELETE /product-shipping-overrides/{id} | shipping:write | K? | Usuń nadpisanie wysyłki produktu. | 404 |
POST /shipping/calculate | shipping:read | - | Wylicz opcje i koszt wysyłki (POST-but-read). | 415,422 |
Klienci
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /customers | customers:read | - | Lista klientów (agregacja po e-mailu; keyset). | 422 |
GET /customers/stats | customers:read | - | Statystyki klientów (KPI). | - |
GET /customers/growth | customers:read | - | Przyrost klientów w czasie (szereg miesięczny). | 422 |
GET /customers/export | customers:read | - | Eksport klientów do CSV (binarny). | 422 |
GET /customers/{email} | customers:read | - | Szczegóły klienta (agregat + adresy). | 404 |
GET /customers/{email}/orders | customers:read | - | Zamówienia klienta (keyset). | 404,422 |
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /email-templates | email:read | - | Lista szablonów e-mail (keyset). | 422 |
GET /email-templates/{id} | email:read | - | Szczegóły szablonu e-mail. | 404 |
GET /email-logs | email:read | - | Lista logów wysłanych e-maili (keyset; PII). | 422 |
POST /email-templates | email:write | K! | Utwórz szablon e-mail (limit planu). | 409,413,415,422 |
PUT /email-templates/{id} | email:write | K? | Zaktualizuj szablon e-mail. | 404,409,413,415,422 |
DELETE /email-templates/{id} | email:write | K? | Usuń szablon e-mail. | 404,409 |
POST /emails/send | email:write | K! | Wyślij wiadomość e-mail (billable; ~10/godz). | 409,413,415,422,502 |
Powiadomienia
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /notifications | notifications:read | - | Lista powiadomień tenant-wide (keyset; ?userId zawęża). | 422 |
GET /notifications/{id} | notifications:read | - | Szczegóły powiadomienia. | 404 |
GET /notifications/unread-count | notifications:read | - | Liczba nieprzeczytanych powiadomień. | 422 |
GET /notification-preferences | notifications:read | - | Preferencje powiadomień (wymaga ?userId=). | 422 |
POST /notifications | notifications:write | K! | Utwórz powiadomienie (odbiorca = członek konta). | 413,415,422 |
POST /notifications/{id}/read | notifications:write | K? | Oznacz powiadomienie jako przeczytane. | 404,409 |
POST /notifications/read-all | notifications:write | K? | Oznacz wszystkie jako przeczytane (wymaga ?userId=). | 409,422 |
Alerty
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /alert-rules | alerts:read | - | Lista reguł alertów (keyset). | 422 |
GET /alert-rules/history | alerts:read | - | Historia wyzwoleń alertów (keyset). | 422 |
GET /alert-rules/{id} | alerts:read | - | Szczegóły reguły alertu. | 404 |
POST /alert-rules | alerts:write | K! | Utwórz regułę alertu. | 413,415,422 |
PUT /alert-rules/{id} | alerts:write | K? | Zaktualizuj regułę alertu. | 404,413,415,422 |
DELETE /alert-rules/{id} | alerts:write | K? | Usuń regułę alertu. | 404,409 |
POST /alert-rules/{id}/toggle | alerts:write | K? | Włącz / wyłącz regułę alertu. | 404,409,422 |
Obsługa posprzedażowa
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /post-sale/capabilities | postsale:read | - | Mapa zdolności posprzedaży per instancja konektora. | - |
GET /post-sale/inbox | postsale:read | - | Zbiorczy inbox (podsumowanie wątków i sporów). | - |
GET /post-sale/conversations | postsale:read | - | Lista wątków (keyset). | 422 |
GET /post-sale/conversations/{id} | postsale:read | - | Szczegóły wątku. | 404 |
GET /post-sale/conversations/{id}/messages | postsale:read | - | Wiadomości w wątku (keyset). | 404,422 |
GET /post-sale/disputes | postsale:read | - | Lista sporów / reklamacji (keyset). | 422 |
GET /post-sale/disputes/{id} | postsale:read | - | Szczegóły sporu. | 404 |
GET /post-sale/disputes/{id}/messages | postsale:read | - | Wiadomości w sporze (keyset). | 404,422 |
GET /post-sale/returns | postsale:read | - | Lista zwrotów (keyset). | 422 |
GET /post-sale/returns/{id} | postsale:read | - | Szczegóły zwrotu. | 404 |
GET /post-sale/refunds | postsale:read | - | Lista zwrotów środków (keyset). | 422 |
POST /post-sale/conversations/{id}/messages | postsale:write | K! | Odpowiedz kupującemu w wątku. | 404,413,415,422,502 |
POST /post-sale/conversations/{id}/read | postsale:write | K? | Oznacz wątek jako przeczytany. | 404,409 |
POST /post-sale/disputes/{id}/messages | postsale:write | K! | Odpowiedz w sporze. | 404,413,415,422,502 |
POST /post-sale/disputes/{id}/status | postsale:write | K! | Zmień status sporu (ruch środków wymaga refunds:write). | 404,413,415,422,502 |
POST /post-sale/returns/{id}/accept | postsale:write | K! | Zaakceptuj zwrot. | 404,409,502 |
POST /post-sale/returns/{id}/reject | postsale:write | K! | Odrzuć zwrot. | 404,413,415,422,502 |
Zwroty środków (izolowany zakres pieniężny)
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
POST /post-sale/refunds/issue | postsale:refunds:write | K! | Realny zwrot środków kupującemu (channel-idempotentne). | 413,415,422,502 |
POST /post-sale/refunds/commission-claim | postsale:refunds:write | K! | Zgłoś zwrot prowizji. | 413,415,422,502 |
Raporty
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /reports/sales | reports:read | - | Raport sprzedaży (szereg czasowy + agregaty, marża). | 422 |
GET /reports/sales/channels | reports:read | - | Podział sprzedaży na kanały. | 422 |
GET /reports/sales/countries | reports:read | - | Podział sprzedaży na kraje. | 422 |
GET /reports/products/bestsellers | reports:read | - | Bestsellery (sprzedaż + marża brutto). | 422 |
GET /reports/products/high-returns | reports:read | - | Produkty z wysokim wskaźnikiem zwrotów. | 422 |
GET /reports/products/low-rotation | reports:read | - | Produkty z niską rotacją. | 422 |
GET /reports/operations/sla | reports:read | - | Metryki SLA realizacji. | 422 |
GET /reports/operations/fulfillment | reports:read | - | Czas realizacji per kanał. | 422 |
GET /reports/export/csv | reports:read | - | Eksport raportu do CSV (binarny). | 422 |
GET /reports/export/xlsx | reports:read | - | Eksport raportu do XLSX (binarny). | 422 |
Monitoring i zużycie
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /monitoring/webhooks | monitoring:read | - | Lista przychodzących webhooków (bez payloadu). | 422 |
GET /monitoring/webhooks/{id} | monitoring:read | - | Szczegół webhooka (surowy payload - PII). | 404 |
GET /monitoring/invoice-links | monitoring:read | - | Powiązania fakturowania (zamówienie -> faktura). | 422 |
GET /monitoring/dlq | monitoring:read | - | Kolejka błędów (dead-letter, bez payloadu). | 422 |
GET /monitoring/dlq/{id} | monitoring:read | - | Szczegół wpisu DLQ (oryginalny payload - PII). | 404 |
GET /monitoring/stats | monitoring:read | - | Zbiorcze statystyki integracji. | - |
GET /usage | monitoring:read | - | Zużycie konta (liczniki, miejsce, limity planu). | - |
POST /monitoring/dlq/{id}/retry | monitoring:write | K! | Ponów wpis DLQ (billable; odpala oryginalny workflow). | 404,409,422 |
Konektory i oferty marketplace
| Operacja | Zakres | Idem. | Cel | Błędy |
|---|---|---|---|---|
GET /connectors | integrations:read | - | Lista konektorów tenanta (projekcja bez sekretów). | - |
GET /warehouse-items/{id}/listings | offers:read | - | Oferty marketplace jednego produktu, osobno dla każdej instancji (keyset). | 404,422 |
GET /category-mappings | offers:read | - | Lista mapowań kategorii (keyset). | 422 |
POST /category-mappings | offers:write | K! | Utwórz mapowanie kategorii (lokalnie). | 409,413,415,422 |
POST /category-mappings/bulk | offers:write | K? | Zbiorczo utwórz mapowania (max 1000). | 409,413,415,422 |
PUT /category-mappings/{id} | offers:write | K? | Przekieruj mapowanie na inny cel. | 404,409,413,415,422 |
DELETE /category-mappings/{id} | offers:write | K? | Usuń mapowanie kategorii. | 404,409 |
POST /category-mappings/sync | offers:write | K? | Odśwież lokalny cache kategorii (billable). | 409,413,415,422,502 |
GET /marketplace/{connectorKey}/products | offers:read | - | Żywa lista produktów z konektora (billable). | 422,502 |
GET /marketplace/{connectorKey}/products/{externalProductId} | offers:read | - | Żywy pojedynczy produkt z konektora (billable). | 502 |
GET /marketplace/{connectorKey}/categories | offers:read | - | Żywe wyszukiwanie kategorii konektora (billable). | 502 |
GET /marketplace/{connectorKey}/categories/{categoryId}/parameters | offers:read | - | Żywe parametry kategorii (billable). | 502 |
GET /marketplace/{connectorKey}/responsible-producers | offers:read | - | Żywa lista producentów GPSR (billable). | 502 |
GET /marketplace/{connectorKey}/responsible-persons | offers:read | - | Żywa lista osób odpowiedzialnych GPSR (billable). | 502 |
POST /warehouse-items/{id}/publish/{connectorKey} | offers:write | K! | Opublikuj ofertę na instancji wskazanej przez configId (billable, realna oferta). | 404,409,413,415,422,502 |
POST /warehouse-items/{id}/sync/{connectorKey} | offers:write | K! | Zaktualizuj ofertę na instancji wskazanej przez configId (billable). | 404,409,413,415,422,502 |
POST /warehouse-items/{id}/pull/{connectorKey} | offers:write | K? | Pobierz ofertę z konektora do katalogu (billable). | 404,409,502 |
POST /warehouse-items/{id}/refresh-status/{connectorKey} | offers:write | K? | Odśwież status jednej oferty (billable). | 404,409,502 |
POST /warehouse-items/refresh-status | offers:write | K? | Zbiorczo odśwież status ofert (max 100). | 409,413,415,422 |
PUT /warehouse-items/{id}/listings/{connectorKey}/pricing | offers:write | K? | Ustaw cenę dla konkretnej instancji z configId (lokalnie, bez wywołania). | 404,409,413,415,422 |
POST /catalog/import | offers:write + catalog:write | K! | Importuj produkt marketplace do magazynu (cross-scope). | 409,413,415,422 |
Paginacja i filtry
Listy stronicujemy kursorowo (bez offsetu). Odpowiedź niesie pagination.nextCursor - przekaż go w parametrze cursor, aby pobrać kolejną stronę. Parametr updatedSince (data-czas ISO ze strefą) zwraca rekordy zmienione od danej chwili. Dla pull-synchronizacji odpytuj z oknem nakładki i deduplikuj po id.
GET /orders?limit=50&cursor=eyJjIjoi...&updatedSince=2026-07-01T00:00:00ZIdempotencja
Operacje zapisu chroni nagłówek Idempotency-Key (dowolny unikat, rekomendowany UUID, do 255 znaków). Jest wymagany na POST /orders i POST /orders/{id}/invoice, a honorowany na PUT i PATCH.
- Powtórka z tym samym kluczem i tą samą treścią zwraca zapisany wynik (nagłówek
Idempotency-Replayed: true) - bez podwójnego efektu. - Ten sam klucz z inną treścią zwraca
409 idempotency_conflict. - Równoległy duplikat w trakcie przetwarzania zwraca
409 idempotency_in_progresszRetry-After. - Klucze wygasają po 24 godzinach.
Przykłady w kodzie
Gotowe fragmenty w trzech wariantach: curl, JavaScript (fetch, Node 20+) i Python (biblioteka requests). Warianty JS i Python zakładają stałe BASE (adres bazowy) i KEY (klucz z bezpiecznego magazynu), ustawione w przykładzie uwierzytelniania.
Uwierzytelnianie (Bearer i X-API-Key)
curl
# Bearer (recommended)
curl https://{your-slug}.navyflame.com/api/public/v1/me \
-H "Authorization: Bearer nf_live_your_key"
# The X-API-Key alias (tools without Bearer support)
curl https://{your-slug}.navyflame.com/api/public/v1/me \
-H "X-API-Key: nf_live_your_key"JavaScript
const BASE = "https://my-shop.navyflame.com/api/public/v1";
const KEY = process.env.NAVYFLAME_API_KEY;
const res = await fetch(BASE + "/me", {
headers: { Authorization: "Bearer " + KEY },
});
if (!res.ok) throw new Error("HTTP " + res.status);
const me = await res.json();
console.log(me.plan, me.scopes);Python
import os, requests
BASE = "https://my-shop.navyflame.com/api/public/v1"
KEY = os.environ["NAVYFLAME_API_KEY"]
r = requests.get(BASE + "/me", headers={"Authorization": "Bearer " + KEY})
r.raise_for_status()
me = r.json()
print(me["plan"], me["scopes"])Paginacja kursorowa (pętla + deduplikacja)
curl
curl "https://{your-slug}.navyflame.com/api/public/v1/orders?limit=100&updatedSince=2026-07-01T00:00:00Z" \
-H "Authorization: Bearer nf_live_your_key"
# the response carries pagination.nextCursor -> pass it as &cursor=... on the next callJavaScript
async function* paginate(path) {
let cursor = null;
do {
const url = new URL(BASE + path);
url.searchParams.set("limit", "100");
if (cursor) url.searchParams.set("cursor", cursor);
const res = await fetch(url, {
headers: { Authorization: "Bearer " + KEY },
});
if (res.status === 429) {
const wait = Number(res.headers.get("Retry-After") || 1);
await new Promise((r) => setTimeout(r, wait * 1000));
continue;
}
if (!res.ok) throw new Error("HTTP " + res.status);
const page = await res.json();
for (const row of page.data) yield row;
cursor = page.pagination.nextCursor;
} while (cursor);
}
const seen = new Set();
for await (const order of paginate("/orders?updatedSince=2026-07-01T00:00:00Z")) {
if (seen.has(order.id)) continue; // deduplicate by id
seen.add(order.id);
// ... process the order
}Python
import time
def paginate(path, params=None):
params = dict(params or {})
params["limit"] = 100
while True:
r = requests.get(BASE + path, params=params,
headers={"Authorization": "Bearer " + KEY})
if r.status_code == 429:
time.sleep(int(r.headers.get("Retry-After", "1")))
continue
r.raise_for_status()
page = r.json()
for row in page["data"]:
yield row
cursor = page["pagination"]["nextCursor"]
if not cursor:
break
params["cursor"] = cursor
seen = set()
for order in paginate("/orders", {"updatedSince": "2026-07-01T00:00:00Z"}):
if order["id"] in seen: # deduplicate by id
continue
seen.add(order["id"])
# ... process the orderIdempotentny zapis (Idempotency-Key + backoff)
curl
curl -X POST "https://{your-slug}.navyflame.com/api/public/v1/orders" \
-H "Authorization: Bearer nf_live_your_key" \
-H "Content-Type: application/json" \
-H "Idempotency-Key: 3f1c9a20-7b2e-4c6d-9f10-000000000001" \
-d '{"customer":{"name":"Jan Kowalski"},"lineItems":[{"title":"Kubek 300 ml","sku":"KUB-300-BIA","quantity":2,"unitPrice":"39.99","taxRate":"23"}],"currency":"PLN"}'JavaScript
import { randomUUID } from "node:crypto";
async function createOrder(body) {
const key = randomUUID(); // the same key on every retry
for (let attempt = 0; attempt < 5; attempt++) {
const res = await fetch(BASE + "/orders", {
method: "POST",
headers: {
Authorization: "Bearer " + KEY,
"Content-Type": "application/json",
"Idempotency-Key": key,
},
body: JSON.stringify(body),
});
if (res.status === 429 || res.status === 502 || res.status === 503) {
const wait = Number(res.headers.get("Retry-After") || 2 ** attempt);
await new Promise((r) => setTimeout(r, wait * 1000));
continue; // transient - retry with the same key
}
if (res.status === 409) {
const problem = await res.json();
if (problem.code === "idempotency_in_progress") {
await new Promise((r) => setTimeout(r, 1000));
continue;
}
throw new Error("idempotency conflict: " + problem.code); // a different body
}
if (!res.ok) throw new Error("HTTP " + res.status);
return res.json(); // 201 or replayed (Idempotency-Replayed: true)
}
throw new Error("wyczerpano proby ponowienia");
}Python
import time
from uuid import uuid4
def create_order(body):
key = str(uuid4()) # the same key on every retry
for attempt in range(5):
r = requests.post(BASE + "/orders", json=body, headers={
"Authorization": "Bearer " + KEY,
"Idempotency-Key": key,
})
if r.status_code in (429, 502, 503):
time.sleep(int(r.headers.get("Retry-After", 2 ** attempt)))
continue # transient - retry with the same key
if r.status_code == 409:
code = r.json().get("code")
if code == "idempotency_in_progress":
time.sleep(int(r.headers.get("Retry-After", "1")))
continue
raise RuntimeError("idempotency conflict: " + str(code))
r.raise_for_status()
return r.json() # 201 or replayed
raise RuntimeError("wyczerpano proby ponowienia")Weryfikację podpisu webhooka (JavaScript i Python) znajdziesz w sekcji Webhooki wychodzące .
Format błędów
Błędy zwracamy zgodnie z RFC 9457 (application/problem+json). Każdy niesie stabilny code i requestId do korelacji ze wsparciem.
{
"type": "https://navyflame.com/dokumentacja/api/bledy#validation_failed",
"title": "Validation failed",
"status": 422,
"detail": "Invalid order input.",
"code": "validation_failed",
"requestId": "req_abc123",
"errors": [{ "field": "lineItems[0].unitPrice", "message": "Kwota >= 0 (jako string)." }]
}| Kod | HTTP | Kiedy | Co zrobić |
|---|---|---|---|
| unauthorized | 401 | Brak, nieprawidłowy, wygasły lub odwołany klucz API. | Sprawdź nagłówek Authorization / X-API-Key. Jeśli klucz odwołany lub wygasły - utwórz nowy w panelu. |
| missing_scope | 403 | Klucz nie ma wymaganego zakresu (np. orders:write) - także cross-scope, gdy operacja wymaga dwóch zakresów. | Nadaj brakujący zakres, rotując klucz z pełnym zestawem zakresów. Zakresów istniejącego klucza nie da się zmienić w miejscu. |
| plan_limit | 403 | Plan nie obejmuje API, wyczerpano limit planu lub subskrypcja wygasła / została anulowana. | Odnów lub podnieś plan. API wraca automatycznie po aktywacji (propagacja limitu do IE w ciągu ok. 5 minut). |
| not_supported | 403 | Operacja wymaga konektora kuriera lub marketplace, który nie jest połączony (capability gate; nigdy 500). | Podłącz i włącz właściwy konektor w panelu (Integracje). Dostępność sprawdzisz w /post-sale/capabilities lub /connectors. |
| not_found | 404 | Zasób nie istnieje w Twoim koncie (lub należy do innego tenanta - nieodróżnialne, anti-IDOR). | Zweryfikuj identyfikator. Cudzy identyfikator zawsze wygląda jak nieistniejący. |
| conflict | 409 | Konflikt stanu zasobu: oferta już opublikowana, duplikat SKU / kodu kreskowego / nazwy, brak stanu, dokument nie w statusie Szkic. | Rozwiąż konflikt: przy publikacji użyj sync zamiast publish; zmień SKU / nazwę; sprawdź status zasobu. |
| idempotency_conflict | 409 | Ten sam Idempotency-Key użyty z inną treścią żądania. | Użyj nowego Idempotency-Key dla nowej treści. Ten sam klucz musi nieść identyczne body. |
| idempotency_in_progress | 409 | Żądanie z tym kluczem jest właśnie przetwarzane (równoległy duplikat). | Poczekaj wg nagłówka Retry-After i ponów z tym samym kluczem. |
| payload_too_large | 413 | Treść żądania przekracza 2 MB. | Zmniejsz body (np. mniejsze partie w operacjach wsadowych). |
| unsupported_media_type | 415 | Zapis bez nagłówka Content-Type: application/json. | Ustaw nagłówek Content-Type: application/json na operacjach zapisu. |
| validation_failed | 422 | Błędne dane wejściowe: zła wartość, niedozwolone przejście statusu, zły cursor, naive datetime bez strefy. | Popraw dane wg pola errors w odpowiedzi (field + message). |
| rate_limited | 429 | Przekroczono limit (planu per konto, per-IP, in-flight lub dedykowany limit wysyłki e-mail). | Zwolnij tempo, uszanuj Retry-After i zastosuj wykładniczy backoff. Sprawdź nagłówki X-RateLimit-*. |
| internal | 500 | Błąd po stronie NavyFlame. | Ponów z backoffem. Przy powtarzalnym błędzie zgłoś requestId do wsparcia. |
| bad_gateway | 502 | Błąd usługi zewnętrznej (przewoźnik, Allegro lub inny marketplace) - traktuj jak przejściowy. | Ponów z backoffem. Przy zapisie ponawiaj z tym samym Idempotency-Key (kanał zdeduplikuje). Zob. uwagi o publikacji i zwrotach. |
| service_unavailable | 503 | Restart, wdrożenie lub konfiguracja jeszcze niegotowa (ciągłe wdrożenia). | Ponów z backoffem - to stan przejściowy. |
Kody 500 (internal) i 503 (service_unavailable) mogą wystąpić na każdej operacji i nie są deklarowane per endpoint. Wdrożenia są ciągłe - klient powinien traktować sporadyczne 502/503 jako przejściowe (ponowienie z backoffem), a operacje zapisu zabezpieczać nagłówkiem Idempotency-Key. Nagłówek type w problem+json wskazuje na kotwicę tej sekcji (np. #validation_failed).
Webhooki wychodzące
Subskrybujesz zdarzenie i podajesz adres HTTPS, a my wysyłamy tam podpisane powiadomienie. Zdarzenia v1: order.synced, order.status_changed, invoice.issued, shipment.status_updated, catalog.updated. Każda dostawa niesie nagłówki X-NavyFlame-Event, X-NavyFlame-Delivery-Id i X-NavyFlame-Signature. Sukces to odpowiedź 2xx w ciągu 5 sekund; przy niepowodzeniu ponawiamy z rosnącym odstępem przez ok. 24 godziny, a historię dostaw widzisz w panelu.
Kształt ładunku (wspólna koperta):
{
"id": "evt_9f4c2f6a-...",
"type": "order.synced",
"apiVersion": "v1",
"occurredAt": "2026-07-07T12:00:00Z",
"tenant": "your-slug",
"origin": { "channel": "api", "apiKeyPrefix": "nf_live_abc123" },
"data": { "order": { }, "isNew": true }
}Pole origin.channel (api | panel | sync | automation) pozwala przerwać pętlę echa - jeśli sam wywołałeś zmianę kluczem API, rozpoznasz to po apiKeyPrefix i pominiesz zdarzenie. Odbiorca deduplikuje po id zdarzenia oraz nagłówku X-NavyFlame-Delivery-Id (gwarancja at-least-once, bez gwarancji kolejności).
Katalog zdarzeń (v1)
Zamknięta lista zdarzeń v1 - nowe typy to zmiana addytywna, więc odbiornik musi ignorować nieznane pola i typy. Każde zdarzenie niesie wspólną kopertę (powyżej); treść specyficzna dla typu jest w polu data:
order.synced - Po zapisaniu zamówienia, tylko przy realnej zmianie danych (nowe zamówienie lub przejście statusu). Pole isNew rozróżnia nowe od zaktualizowanego.
{
"id": "evt_9f4c2f6a-1b2c-4d3e-8a9b-000000000001",
"type": "order.synced",
"apiVersion": "v1",
"occurredAt": "2026-07-09T12:00:00Z",
"tenant": "my-shop",
"origin": { "channel": "sync" },
"data": {
"order": { "id": "0e6b7c...", "orderNumber": "2026/07/000123",
"status": "Processing", "totalPrice": "129.99", "currency": "PLN" },
"isNew": false
}
}order.status_changed - Po zatwierdzonym zapisie realnej zmiany statusu, niezależnie od źródła. Ustawienie tego samego statusu i odrzucone przejście nie wysyłają zdarzenia. Pole order zawiera stan po zapisie, previousStatus status sprzed zapisu, a origin wskazuje źródło zmiany.
{
"id": "evt_2b3c4d5e-6f70-4a8b-9c0d-000000000005",
"type": "order.status_changed",
"apiVersion": "v1",
"occurredAt": "2026-08-30T10:30:00Z",
"tenant": "my-shop",
"origin": { "channel": "api", "apiKeyPrefix": "nf_live_abc123" },
"data": {
"order": { "id": "0e6b7c...", "orderNumber": "2026/08/000321",
"status": "Processing", "totalPrice": "129.99", "currency": "PLN" },
"previousStatus": "New"
}
}invoice.issued - Po wystawieniu faktury w systemie księgowym tenanta.
{
"id": "evt_1a2b3c4d-5e6f-4a7b-8c9d-000000000002",
"type": "invoice.issued",
"apiVersion": "v1",
"occurredAt": "2026-07-09T12:03:00Z",
"tenant": "my-shop",
"origin": { "channel": "automation" },
"data": {
"invoice": { "id": "7a1c9e...", "number": "FV/2026/07/45",
"status": "Issued", "grossAmount": "129.99", "currency": "PLN" }
}
}shipment.status_updated - Po zmianie statusu przesyłki u przewoźnika. Pole previousStatus niesie poprzedni status (lub null).
{
"id": "evt_2b3c4d5e-6f7a-4b8c-9d0e-000000000003",
"type": "shipment.status_updated",
"apiVersion": "v1",
"occurredAt": "2026-07-09T12:10:00Z",
"tenant": "my-shop",
"origin": { "channel": "sync" },
"data": {
"shipment": { "id": "b2d9f1...", "courierProvider": "inpost",
"status": "InTransit", "trackingNumber": "6800000000001" },
"previousStatus": "PickedUp"
}
}catalog.updated - Po zmianie produktu lub stanu. Zmiany pojedyncze jako per-item; operacje jawnie masowe (import hurtowni, bulk) jako jedno zdarzenie zbiorcze (bulk: true).
{
"id": "evt_3c4d5e6f-7a8b-4c9d-0e1f-000000000004",
"type": "catalog.updated",
"apiVersion": "v1",
"occurredAt": "2026-07-09T12:15:00Z",
"tenant": "my-shop",
"origin": { "channel": "api", "apiKeyPrefix": "nf_live_abc123" },
"data": {
"warehouseItemId": "c4e1a2...", "sku": "KUB-300-BIA",
"changeType": "updated", "stockQuantity": 42
}
}
// The bulk variant (data):
// { "bulk": true, "source": "wholesale-import", "itemsChanged": 128 }Weryfikacja podpisu
Nagłówek X-NavyFlame-Signature ma postać t=<unix>,v1=<hex>, gdzie v1 = HMAC-SHA256(sekret, "<t>." + surowe_body). Nagłówek może zawierać kilka par v1= (okno rotacji sekretu - stary i nowy sekret podpisują równolegle przez 24 h) - zaakceptuj dowolną pasującą. Sprawdzaj zgodność znacznika czasu (tolerancja 300 s), aby chronić się przed powtórką.
JavaScript (Node)
import crypto from "node:crypto";
function verify(signatureHeader, rawBody, secret) {
const parts = Object.create(null);
const sigs = [];
for (const p of String(signatureHeader).split(",")) {
const [k, v] = p.split("=");
if (k === "t") parts.t = v;
if (k === "v1" && v) sigs.push(v);
}
if (!parts.t || sigs.length === 0) return false;
if (Math.abs(Date.now() / 1000 - Number(parts.t)) > 300) return false;
const computed = crypto
.createHmac("sha256", secret)
.update(parts.t + "." + rawBody)
.digest("hex");
return sigs.some(
(s) =>
s.length === computed.length &&
crypto.timingSafeEqual(
Buffer.from(computed, "hex"),
Buffer.from(s, "hex"),
),
);
}Python
import hashlib, hmac, time
def verify(signature_header, raw_body, secret):
t = None
sigs = []
for part in signature_header.split(","):
k, _, v = part.partition("=")
if k == "t":
t = v
elif k == "v1" and v:
sigs.append(v)
if not t or not sigs:
return False
if abs(time.time() - int(t)) > 300: # replay protection
return False
computed = hmac.new(
secret.encode(), (t + "." + raw_body).encode(), hashlib.sha256
).hexdigest()
return any(hmac.compare_digest(computed, s) for s in sigs)Weryfikuj podpis na surowym ciele żądania (bajty przed parsowaniem JSON) - ponowne serializowanie zmieni bajty i podpis się nie zgodzi. raw_body / rawBody to dokładne bajty odebrane w ciele POST, przed dekodowaniem JSON.
Recepta na Zapier i Make
- W Zapier utwórz Zap z triggerem Webhooks by Zapier - Catch Hook (w Make: moduł Custom Webhook). Skopiuj wygenerowany adres.
- W panelu NavyFlame (Konto - API - Webhooki) dodaj subskrypcję: wybierz zdarzenie i wklej adres jako cel. Sekret podpisu zobaczysz raz - zapisz go.
- Użyj przycisku Wyślij test w panelu, aby potwierdzić, że scenariusz odbiera ładunek.
- (Zalecane) Dodaj krok weryfikacji podpisu powyższą funkcją, zanim zaufasz danym.
RODO
Ładunki webhooków niosą dane osobowe kupujących. Konfigurując subskrypcję (wybór adresu docelowego, np. Zapier - zwykle transfer poza EOG) występujesz jako administrator tych danych, a subskrypcja jest Twoim udokumentowanym poleceniem przetwarzania. Propagacja usunięcia lub anonimizacji danych kupującego do systemów zasilonych przez API i webhooki jest po Twojej stronie.
Przewodniki
Szybki start (od klucza do pierwszego wywołania)
- W panelu (Konto - API) utwórz klucz z potrzebnymi zakresami. Klucz zobaczysz tylko raz - zapisz go w bezpiecznym magazynie sekretów.
- Potwierdź połączenie:
GET /me(nie wymaga zakresu). Zwraca plan, limity i zakresy klucza. - Wykonaj pierwsze wywołanie w docelowym zasobie, np.
GET /orders?limit=25.
Pull-synchronizacja (updatedSince + okno nakładki + dedupe)
- Odpytuj z
updatedSince = ostatni_sync - okno_nakładki(np. 5 minut). Semantyka jest inclusive (>=), precyzja milisekundowa. - Paginuj kursorowo aż
pagination.nextCursorbędzienull. - Deduplikuj po
id- samo>=nie chroni przed rekordem, którego transakcja commitowała po Twoim odczycie (stąd okno nakładki). - Zapisz najwyższy
updatedAtze strony jako punkt startu następnego przebiegu. - Po przywróceniu konta z kopii zapasowej wykonaj pełny resync - nie polegaj na
updatedSince(i utwórz nowe klucze).
Zapier i Make (webhook do akcji)
- W Zapier utwórz trigger Webhooks by Zapier - Catch Hook (w Make: Custom Webhook) i skopiuj wygenerowany adres.
- W panelu (Konto - API - Webhooki) dodaj subskrypcję: wybierz zdarzenie, wklej adres jako cel, zapisz sekret (pokazany raz).
- Kliknij Wyślij test w panelu, aby potwierdzić odbiór ładunku.
- Dodaj krok weryfikacji podpisu (patrz sekcja Webhooki), zanim zaufasz danym.
- Do wywołań zwrotnych do API użyj modułu HTTP / Custom Request z nagłówkiem
Authorization: Bearer.
Rotacja klucza i sekretu webhooka (okno 24 h)
- Klucz API: rotacja w panelu zwraca nowy token raz; stary działa jeszcze 24 h (zero-downtime) - podmień go w integracji w tym oknie. Odwołanie (revoke) jest skuteczne natychmiast.
- Sekret webhooka: rotacja ma okno overlap - stary i nowy sekret podpisują równolegle przez 24 h. Nagłówek podpisu może nieść wiele par
v1=, więc akceptowanie dowolnej pasującej sprawia, że rotacja nie jest zmianą łamiącą. - Po restore z backupu klucze API są automatycznie odwoływane - utwórz nowe i wykonaj pełny resync.
Obsługa limitów (Retry-After + backoff)
- Odczytaj limit planu z
GET /me(rateLimitPerMin) lubGET /usage. Limity są agregowane per konto, nie per klucz. - Każda odpowiedź niesie
X-RateLimit-Limit,X-RateLimit-RemainingiX-RateLimit-Reset- steruj tempem na bieżąco. - Na
429uszanujRetry-After(sekundy) i zastosuj wykładniczy backoff. Trzymaj współbieżność poniżej limitu in-flight (20 równoległych żądań per konto). - Enterprise ma limit per-minuta wyłączony; per-IP flood guard i cap współbieżności działają zawsze (ochrona infrastruktury, nie plan).
Wersjonowanie i zmiany
Wersja jest w ścieżce (/api/public/v1). Zmiany addytywne (nowe pola, nowe endpointy, nowe typy zdarzeń) nie łamią zgodności - Twój klient musi ignorować nieznane pola. Zmiany łamiące zapowiadamy z wyprzedzeniem: wpis w changelogu, e-mail do właścicieli aktywnych kluczy oraz nagłówki Deprecation i Sunset.
Changelog
Historia wersji v1 (numer wersji = kolejna faza rozbudowy). Wszystkie zmiany są addytywne - nie usunęliśmy ani nie zmieniliśmy znaczenia żadnego endpointu ani pola. Aktualna wersja specyfikacji OpenAPI: v1.10.0.
| Wersja | Faza | Co doszło (addytywnie) |
|---|---|---|
| v1.0 | GA | Rdzeń API: /me, zamówienia (odczyt + zapis + fakturowanie), magazyn (odczyt + PATCH stanu), faktury (odczyt), przesyłki (odczyt). Webhooki: order.synced, invoice.issued, shipment.status_updated, catalog.updated. Paginacja keyset, idempotencja, błędy RFC 9457. |
| v1.1 | Faza A | Analityka read-only: raporty sprzedaży / produktów / operacji (+ eksport CSV/XLSX), AI-Ops, monitoring, zużycie oraz statystyki i historia statusów zamówień. |
| v1.2 | Faza B | Dane osobowe read-only: klienci, szablony i logi e-mail, powiadomienia i preferencje, reguły alertów, obsługa posprzedażowa. |
| v1.3 | Faza C | Zapis katalogu: produkty (CRUD), magazyny i lokalizacje, rezerwacje, dokumenty magazynowe, zestawy, szablony (opisów i produktów) oraz treści AI (billable). |
| v1.4 | Faza D1 | Zapis konfiguracji wysyłki: reguły, strefy ze stawkami, opcje dostawy, nadpisania per produkt oraz kalkulator kosztów. |
| v1.5 | Faza D2 | Lifecycle przesyłek i kurier: tworzenie (pojedynczo i zbiorczo), zakup etykiety (billable), anulowanie, tracking, push do Allegro oraz odczyty pomocnicze kuriera (etykieta PDF, punkty, usługi, terminy). |
| v1.6 | Faza E1 | Odkrywanie konektorów (bez sekretów) oraz lokalne odczyty ofert marketplace i mapowań kategorii. |
| v1.7 | Faza E2 | Żywe, płatne odczyty marketplace (produkty, kategorie, GPSR) oraz zapis mapowań kategorii (+ synchronizacja cache). |
| v1.8 | Faza E3 | Publikacja, synchronizacja, pull, import i cennik per kanał realnych ofert marketplace (billable). |
| v1.9 | Faza F | Zapis komunikacji i posprzedaży: powiadomienia, alerty, e-mail (wysyłka billable), ponowne przetwarzanie DLQ oraz obsługa posprzedażowa i zwroty środków (izolowany zakres postsale:refunds:write). |
| v1.10 | Webhooki | Nowe zdarzenie order.status_changed po zatwierdzonej realnej zmianie statusu zamówienia, z previousStatus i origin. Brak zdarzenia dla no-op i odrzuconego przejścia. |
Wersjonowanie jest w ścieżce: zmiana łamiąca trafiłaby do /v2 z równoległym wsparciem v1 przez min. 6 miesięcy od ogłoszenia (wpis w changelogu, e-mail do właścicieli aktywnych kluczy oraz nagłówki Deprecation i Sunset).
Dobre praktyki
- Testuj połączenie na
GET /meprzed pierwszą integracją. - Zawsze dołączaj
Idempotency-Keydo operacji zapisu i ponawiaj przejściowe błędy z backoffem. - Po przywróceniu konta z kopii zapasowej wykonaj pełną resynchronizację (nie polegaj na
updatedSince) i utwórz nowe klucze - stare są po restore unieważniane. - Do pull-synchronizacji używaj
updatedSincez oknem nakładki i deduplikuj poid.
Najczęściej zadawane pytania
Zaloguj się do panelu, wejdź w Konto - API i utwórz klucz z potrzebnymi zakresami. Klucz zobaczysz tylko raz - zapisz go bezpiecznie. Pierwszy test wykonaj na GET /me, aby potwierdzić połączenie i zobaczyć swój plan oraz limity.
Klucz API służy do wywołań przychodzących - Twój system odpytuje NavyFlame o dane lub wykonuje operacje. Webhook to powiadomienie wychodzące - to NavyFlame wysyła do Ciebie sygnał o zdarzeniu (np. nowe zamówienie), gdy tylko ono nastąpi.
Do odbierania webhooków użyj modułu Webhooks (Zapier) lub Custom Webhook (Make) - podaj adres jako cel subskrypcji w panelu. Do wywołań API użyj modułu HTTP / Custom Request z nagłówkiem Authorization: Bearer. Weryfikację podpisu opisujemy w sekcji Webhooki.
Nie, jeśli użyjesz nagłówka Idempotency-Key. Powtórzenie żądania z tym samym kluczem zwróci ten sam wynik bez podwójnego efektu. Nagłówek jest wymagany przy tworzeniu zamówień i wyzwalaniu fakturowania.
API zwraca 403 z kodem plan_limit do czasu odnowienia. Po przywróceniu konta z kopii zapasowej klucze API są automatycznie unieważniane (utwórz nowe) i zalecamy pełną resynchronizację danych zamiast polegania na updatedSince.
Gotowy, aby zintegrować swój system?
Załóż konto, utwórz klucz API w panelu i zacznij od GET /me.