Zadanie multimedialne przeżywa wywołanie HTTP, które je utworzyło, stronę, która je uruchomiła, a często i wdrożenie działające w tamtej chwili. Wszystko tutaj służy temu, żeby dało się to przeżyć.
Między naciśnięciem „wyślij” a plikiem w ręku są cztery miejsca, w których gubi się pracę: utworzenie zakończone timeoutem, ponawiane na ślepo, wywołanie zwrotne, którego nie da się uwierzytelnić, pętla odpytywania, która albo młóci, albo się poddaje, i adres wyniku, który wygasł w trakcie namysłu, co z nim zrobić.
01
Ponowione utworzenie bez klucza to drugi rachunek
Idempotency-Key sprawia, że powtórzenie tego samego modelu, wejścia i wywołania zwrotnego w ciągu 24 godzin zwraca pierwotne zadanie, zamiast blokować środki po raz drugi. Działa w zakresie jednego klucza API – bliźniaczy klucz powtarzający tę samą wartość dostaje 409 i żadnego identyfikatora zadania.
02
Niezweryfikowane wywołanie zwrotne to otwarty endpoint
Dostarczenia niosą X-Webhook-Timestamp i zakodowany w Base64 HMAC-SHA256 w X-Webhook-Signature, liczony z taskId.timestamp.sha256(raw_body). Weryfikuj na surowych bajtach w stałym czasie i odrzucaj przeterminowane znaczniki czasu, zanim ruszysz stan zadania albo rozliczeń.
03
Odpytywanie bez sufitu to limit żądań czekający, aż się wydarzy
recordInfo to zabezpieczenie, a nie transport. Zacznij od mniej więcej dwóch sekund, wydłużaj odstęp o połowę, zatrzymaj się na piętnastu i przerwij w terminie wybranym przez siebie, a nie przez sieć.
Podejście
Jeden trwały rekord na zadanie, zapisany przed odpowiedzią
Zapisz klucz idempotentności, taskId i własny identyfikator korelacji w tej samej transakcji, która odpowiada wołającemu. Każde późniejsze zdarzenie – wywołanie zwrotne, odpytanie, ponowienie, pytanie od wsparcia – rozstrzyga się na tym wierszu, a zdublowane dostarczenie staje się aktualizacją zamiast drugim zamówieniem.
Najpierw weryfikuj, potem czytaj. Podpis obejmuje surowe bajty, więc parsuj dopiero po udanym porównaniu.
Verify the callback before you trust it
import { createHash, createHmac, timingSafeEqual } from "node:crypto";
// rawBody is the exact bytes that arrived. Parse only to read the task ID:
// the digest is always computed over those raw bytes, never over a re-encode.
export function verifyDelivery(rawBody, headers, webhookKey) {
const timestamp = headers["x-webhook-timestamp"];
if (Math.abs(Date.now() / 1000 - Number(timestamp)) > 300) return false;
const taskId = JSON.parse(rawBody).data.taskId; // payload version 2
const digest = createHash("sha256").update(rawBody).digest("hex");
const expected = createHmac("sha256", webhookKey)
.update(`${taskId}.${timestamp}.${digest}`)
.digest("base64");
const sent = Buffer.from(headers["x-webhook-signature"] ?? "", "utf8");
const mine = Buffer.from(expected, "utf8");
return sent.length === mine.length && timingSafeEqual(sent, mine);
}
Asynchroniczne API mediów: zadania i webhooki — Co warto ustalić na starcie
Pole lub nagłówek
Wartość lub limit
Idempotency-Key
24 h · scoped to one API key
X-Webhook-Signature
base64(HMAC-SHA256)
signed string
taskId.timestamp.sha256(raw_body)
X-Webhook-Payload-Version
2 for new integrations
Przesuń w poziomie, żeby zobaczyć wszystkie kolumny.
Integracja
Od pierwszego wywołania do produkcji
01Wygeneruj i zapisz klucz idempotentności, a potem wyślij POST createTask z nim oraz z callBackUrl wskazującym endpoint HTTPS na porcie 80 albo 443.
02Zapisz data.taskId w swojej bazie, zanim odpowiesz wołającemu – w odpowiedzi 202 pojawia się on po raz pierwszy.
03Przyjmij wywołanie zwrotne, zweryfikuj podpis na surowej treści, odfiltruj duplikaty po request_id i zaktualizuj swój rekord.
04W razie potrzeby sięgnij po recordInfo z wykładniczym odstępem i skopiuj output.assets do własnego magazynu, zanim podpisany adres wygaśnie.
Dopasowanie
Kiedy ta droga jest właściwa
Wybierz to, gdy
Wszystko, co tworzy media. Endpointy obrazu, wideo i dźwięku są asynchroniczne z założenia.
Potrzebujesz trwałego zapisu tego, co wysłano, ile to miało kosztować i jak się skończyło.
Poszukaj gdzie indziej, gdy
Wołasz model tekstowy. Te strumieniują w obrębie żądania i rozliczają się na zmierzonym zużyciu.
Chcesz, żeby zadanie należało do przeglądarki. Klucze mają być po stronie twojego serwera, podobnie jak rekord zadania.
Dowody
Co możesz sprawdzić samodzielnie
Każda odpowiedź niesie request_id
Struktura odpowiedzi to {code, msg, data, request_id} przy każdej operacji /api/v1. W wersji 2 ładunku request_id dostarczenia pozostaje stabilny między ponowieniami, co czyni go naturalnym kluczem deduplikacji.
Blokady widać w rekordzie
cost z settled: false to zarezerwowana wycena, a settled: true to końcowa opłata. Powodzenie nigdy nie przekracza blokady, a niepowodzenie albo wygaśnięcie zwalnia ją w całości.
Błędy mają zamknięty słownik
errorCode to jedna z dziewięciu stabilnych wartości: invalid_request, unsupported_combination, content_rejected, rate_limited, upstream_unavailable, generation_failed, timeout, invalid_asset, upstream_failed. Wszystko inne traktuj jak upstream_failed.
Przed startem
Zachowania platformy do potwierdzenia
Trzymaj klucz idempotentności razem z zadaniem, a nie w pamięci procesu.
Zrób obsługę wywołania zwrotnego idempotentną – dostarczenia są ponawiane z założenia.
Ustaw termin dla odpytywania i alarmuj o zadaniach, które go przekroczą.
Kopiuj pliki przed expiresAt i proś o nowy adres, zamiast buforować podpisany.
FAQ
O co pytają na tej stronie
Ponów to samo żądanie z tym samym nagłówkiem Idempotency-Key. W ciągu 24 godzin i na tym samym kluczu API wróci pierwotne zadanie bez drugiej blokady. Nigdy nie wysyłaj po timeoucie nowej treści – to już osobne, osobno płatne zadanie.
Jedno i drugie. Wywołanie zwrotne to szybka ścieżka, a ograniczone odpytywanie to zabezpieczenie na wypadek dostarczenia, które nigdy nie dotarło. Pętla odpytywania nigdy nie powinna być podstawowym transportem.
Policz HMAC-SHA256 z taskId.timestamp.sha256(raw_body) kluczem webhooka swojego konta, zakoduj w Base64 i porównaj w stałym czasie. W wersji 2 ładunku identyfikator zadania pochodzi z data.taskId.
Nie. Przyjęcie jest ostateczne. Stan canceled istnieje po to, żeby dawne rekordy dało się czytać – to nie jest akcja, którą można wywołać.
Modele
Modele, które możesz tu wywołać
Każdy odnośnik prowadzi na stronę danej rodziny modeli: wejścia, limity, zasady dotyczące treści i aktualna cena za jednostkę.