Protokół webhook

Kontrakt powiadomień webhook — format danych, podpis HMAC, ponowienia i wyłącznik bezpieczeństwa.

Gdy zadanie się kończy (completed, failed lub cancelled), wysyłamy powiadomienie POST na callback_url Twojej instalacji. Ta strona opisuje kontrakt powiadomień; praktyczny przewodnik z kodem weryfikacji znajdziesz w samouczku o odbieraniu wyników.

Format powiadomienia

{
  "event": "job.completed",
  "delivered_at": "2026-06-03T08:00:00.000Z",
  "job": {
    "id": "00000000-0000-0000-0000-0000000000a1",
    "status": "completed",
    "order_id": "00000000-0000-0000-0000-000000000099",
    "completed_at": "2026-06-03T07:59:40.000Z",
    "error": null
  },
  "outputs": [
    {
      "url": "https://…?token=…",
      "type": "image/jpeg",
      "width": 1024,
      "height": 1280
    }
  ],
  "external_metadata": { "your": "tag" }
}
  • eventjob.completed, job.failed lub job.cancelled.
  • outputs[].url — adresy pobrania ważne co najmniej 7 dni; świeże uzyskasz przez POST /jobs/{id}/refresh-url.
  • external_metadata — wraca dokładnie to, co wysłałeś przy tworzeniu sesji.

Podpis

Każde powiadomienie zawiera nagłówek:

X-Qamera-Signature: t=<czas-unix>,v1=<hmac_sha256_hex>

Podpisywany jest ciąg <t>.<surowe-body> sekretem HMAC instalacji (algorytm HMAC-SHA256, wynik w hex). Odrzucaj powiadomienia, których t jest starsze niż 5 minut. Gotowe funkcje weryfikujące w Node.js i PHP znajdziesz w samouczku.

Okno wymiany sekretu

Po wymianie sekretu przez POST /installations/{id}/rotate-hmac poprzedni sekret działa jeszcze 48 godzin. W tym oknie powiadomienia mają dwa segmenty v1= — po jednym na każdy sekret; zaakceptuj dowolny z nich:

X-Qamera-Signature: t=1746777600,v1=e3b0…,v1=44a0…

Po zakończeniu okna podpisujemy wyłącznie nowym sekretem.

Gwarancje niezawodności

  • Do 8 prób dostarczenia, z rosnącym odstępem (z losowym rozrzutem), maksymalnie 1 godzina między próbami.
  • 5 kolejnych nieudanych dostarczeń wstrzymuje wysyłkę na 30 minut (wyłącznik bezpieczeństwa).
  • 3 takie cykle zawieszają instalację — odwieszenie wymaga administratora.
  • Po wyczerpaniu prób powiadomienie dostaje status abandoned i można je wysłać ponownie przez POST /webhooks/{delivery_id}/replay.

Twój endpoint powinien:

  1. Odpowiadać dowolnym statusem 2xx dla przyjętych powiadomień.
  2. Przetwarzać idempotentnie — po wolnej odpowiedzi 200 możemy ponowić wysyłkę już dostarczonego powiadomienia.
  3. Zapisywać (event, job.id, delivered_at) do diagnostyki — już potwierdzonych powiadomień nie wysyłamy ponownie z własnej inicjatywy.