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://{twoj-slug}.navyflame.com/api/public/v1

Peł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://{twoj-slug}.navyflame.com/api/public/v1/me \
  -H "Authorization: Bearer nf_live_twoj_klucz"

Przykładowa odpowiedź:

{
  "tenant": "twoj-slug",
  "keyPrefix": "nf_live_abc123",
  "scopes": ["orders:read", "orders:write"],
  "plan": "Professional",
  "rateLimitPerMin": 300,
  "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_twoj_klucz
# lub
X-API-Key: nf_live_twoj_klucz

Klucze 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.

ZakresUprawnia do
orders:readOdczyt zamówień (lista, szczegóły).
orders:writeZmiana statusu, tworzenie zamówień, wyzwalanie fakturowania.
catalog:readOdczyt produktów magazynowych.
catalog:writeKorekta stanu magazynowego.
invoices:readOdczyt faktur.
shipments:readOdczyt przesyłek.

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.

PlanKlucze APIZapytaniaWebhooki
Basic260 / min5
Professional10300 / min25
EnterpriseBez limitu1000 / minBez limitu

Zasoby i operacje

Odczyt (paginacja kursorowa, filtry, sortowanie):

GET /orders            GET /orders/{id}
GET /warehouse-items   GET /warehouse-items/{id}
GET /invoices          GET /invoices/{id}
GET /shipments         GET /shipments/{id}

Zapis:

PUT   /orders/{id}/status            # zmiana statusu (macierz przejść)
POST  /orders                        # utworzenie zamówienia (source: api)
POST  /orders/{id}/invoice           # wyzwolenie fakturowania
PATCH /warehouse-items/{id}/stock    # korekta stanu (set / adjust)

Przykład - lista ostatnich zamówień:

curl "https://{twoj-slug}.navyflame.com/api/public/v1/orders?limit=25" \
  -H "Authorization: Bearer nf_live_twoj_klucz"

Przykład - korekta stanu magazynowego o -3 sztuki (atomowo):

curl -X PATCH \
  "https://{twoj-slug}.navyflame.com/api/public/v1/warehouse-items/{id}/stock" \
  -H "Authorization: Bearer nf_live_twoj_klucz" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: 6f9a...-unikat" \
  -d '{"operation":"adjust","quantity":-3}'

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:00Z

Idempotencja

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_progress z Retry-After.
  • Klucze wygasają po 24 godzinach.

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": "Walidacja nie powiodła się",
  "status": 422,
  "detail": "Nieprawidłowe dane wejściowe zamówienia.",
  "code": "validation_failed",
  "requestId": "req_abc123",
  "errors": [{ "field": "lineItems[0].unitPrice", "message": "Kwota >= 0 (jako string)." }]
}
KodHTTPKiedy
unauthorized401Brak lub nieprawidłowy klucz API.
missing_scope403Klucz nie ma wymaganego zakresu (np. orders:write).
plan_limit403Subskrypcja wygasła lub plan nieaktywny.
not_found404Zasób nie istnieje w Twoim koncie.
idempotency_conflict409Ten sam Idempotency-Key użyty z inną treścią.
idempotency_in_progress409Żądanie z tym kluczem jest właśnie przetwarzane (ponów).
payload_too_large413Treść żądania przekracza 2 MB.
unsupported_media_type415Brak nagłówka Content-Type: application/json.
validation_failed422Błędne dane wejściowe (szczegóły w polu errors).
rate_limited429Przekroczono limit zapytań (patrz Retry-After).

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.

Webhooki wychodzące

Subskrybujesz zdarzenie i podajesz adres HTTPS, a my wysyłamy tam podpisane powiadomienie. Zdarzenia v1: order.synced, 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": "twoj-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.

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) - zaakceptuj dowolną pasującą. Sprawdzaj zgodność znacznika czasu (tolerancja 300 s), aby chronić się przed powtórką.

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"),
      ),
  );
}

Weryfikuj podpis na surowym ciele żądania (bajty przed parsowaniem JSON) - ponowne serializowanie zmieni bajty i podpis się nie zgodzi.

Recepta na Zapier i Make

  1. W Zapier utwórz Zap z triggerem Webhooks by Zapier - Catch Hook (w Make: moduł Custom Webhook). Skopiuj wygenerowany adres.
  2. W panelu NavyFlame (Konto - API - Webhooki) dodaj subskrypcję: wybierz zdarzenie i wklej adres jako cel. Sekret podpisu zobaczysz raz - zapisz go.
  3. Użyj przycisku Wyślij test w panelu, aby potwierdzić, że scenariusz odbiera ładunek.
  4. (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.

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.

Dobre praktyki

  • Testuj połączenie na GET /me przed pierwszą integracją.
  • Zawsze dołączaj Idempotency-Key do 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 updatedSince z oknem nakładki i deduplikuj po id.

Najczesciej 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.

Załóż konto