APIMaster Webhooki dla zadań asynchronicznych
Otrzymuj podpisane powiadomienia o ukończeniu i niepowodzeniu dla Seedance, zadań wideo i asynchronicznych zadań graficznych, z ponownymi próbami dostarczenia, historią dostaw i rezerwowym odpytywaniem.
Webhooki APIMaster dla zadań asynchronicznych
Używaj webhooków jako głównego mechanizmu powiadomień dla generowania asynchronicznego, a odpytywanie traktuj jako rezerwę. APIMaster wysyła podpisane żądanie HTTPS POST, gdy śledzone zadanie zostanie ukończone lub zakończy się niepowodzeniem. Powiadomienia są niezależne od dostawcy generowania i wykorzystują identyfikator zadania APIMaster.
Obsługiwane modele i punkty końcowe
Seedance obejmuje wszystkie cztery modele: seedance-2.0, seedance-2.5, seedance-2.0-fast i seedance-2.0-mini. Użyj POST /v1/videos/generations lub kompatybilnego POST /v1/video/generations.
Powiadomienia o zadaniach wideo obsługują również MiniMax-H3, Kling Omni / Motion Control, Grok Imagine Video i Sora. Obsługiwane przepływy pracy GPT Image 2 / 2.5 i Gemini wykorzystują /v1/images/generations/async lub obsługiwany /v1/images/edits/async; Midjourney v8.2 / Niji 7 wykorzystują /v1/midjourney/generations. Dostępność tras i parametry generowania nadal podlegają przewodnikowi każdego modelu. Synchroniczne generowanie Seedream i Grok, przesyłanie strumieniowe czatu oraz przegląd zasobów Seedance nie są częścią tej umowy webhookowej dotyczącej generowania.
Sprawdź GET /v1/webhook-capabilities?model=seedance-2.0-fast pod kątem kwalifikowalności modelu. Użyj obsługiwanego asynchronicznego punktu końcowego zgłoszenia; kwalifikowalność nie oznacza, że każda operacja na obrazach lub każdy alias modelu obsługuje generowanie asynchroniczne.
Zarejestruj i zweryfikuj punkt końcowy
Użyj swojego klucza API w Authorization: Bearer YOUR_API_KEY. Klucz API może zarządzać punktami końcowymi i zdarzeniami należącymi do jego konta. Przechowuj go na swoim serwerze.
curl --fail-with-body "https://apimaster.ai/v1/webhook-endpoints" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{"url":"https://your-server.example/webhooks/apimaster"}'
Odpowiedź zawiera endpoint.id, endpoint.key_id i signing_secret. Bezpiecznie zapisz tajny klucz podpisywania: jest zwracany tylko raz. Jest oddzielony od Twojego klucza API i nie może autoryzować generowania ani pobierania. Adres URL musi być publicznie dostępnym punktem końcowym HTTPS na porcie 443. Adresy prywatne i przekierowania są odrzucane. Dozwolonych jest do 20 punktów końcowych na konto; adresy URL są niezmienne, więc utwórz i zweryfikuj nowy punkt końcowy przy zmianie miejsca docelowego.
Po skonfigurowaniu odbiorcy zweryfikuj własność:
curl --fail-with-body -X POST "https://apimaster.ai/v1/webhook-endpoints/whep_example/verify" \
-H "Authorization: Bearer YOUR_API_KEY"
APIMaster wysyła podpisane zdarzenie webhook.endpoint_verification zawierające data.challenge. Zwróć HTTP 200 z {"challenge":"THE_RECEIVED_CHALLENGE"} w ciągu 10 sekund. Żądanie generowania odwołujące się do niezweryfikowanego, wstrzymanego lub należącego do innego konta punktu końcowego zostanie odrzucone przed przesłaniem.
Łączny limit czasu żądania HTTP wynosi 10 sekund, wliczając DNS, połączenie i TLS. Nagłówki odpowiedzi muszą dotrzeć w ciągu 8 sekund od wysłania żądania. Zapisz zdarzenie trwale i natychmiast potwierdź odbiór.
Prześlij zadanie z powiadomieniami
curl --fail-with-body "https://apimaster.ai/v1/videos/generations" \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model":"seedance-2.5",
"prompt":"A paper boat floating on a calm pond, slow camera movement.",
"duration":4,
"resolution":"480p",
"aspect_ratio":"16:9",
"notifications":{
"webhook":{
"endpoint_id":"whep_example",
"events":["task.completed","task.failed"]
}
},
"client_reference_id":"order_123"
}'
Zastąp identyfikator modelu dowolnym z czterech identyfikatorów Seedance, zachowując jego własne obsługiwane parametry. Zapisz identyfikator zadania z normalnej odpowiedzi utworzenia. client_reference_id to opcjonalne odwołanie biznesowe o długości co najwyżej 128 bajtów; nie jest to klucz idempotentności zgłoszenia. Nie łącz notifications z przestarzałymi parametrami dostawcy webhook lub callback_url.
Dla obsługiwanych wieloczęściowych edycji obrazów wyślij notifications jako pole formularza typu ciąg JSON i client_reference_id jako oddzielne pole formularza:
curl --fail-with-body "https://apimaster.ai/v1/images/edits/async" \
-H "Authorization: Bearer YOUR_API_KEY" \
-F "model=gpt-image-2" \
-F "prompt=Turn the reference into a watercolor illustration" \
-F "image=@reference.png" \
-F 'notifications={"webhook":{"endpoint_id":"whep_example","events":["task.completed","task.failed"]}}' \
-F "client_reference_id=image_order_123"
W tej wersji nie ma domyślnego punktu końcowego na poziomie konta: odwołuj się do punktu końcowego w każdym żądaniu zadania. Webhooki mogą dotrzeć przed odpowiedzią na Twoje zgłoszenie. Zachowuj je nawet jeśli Twoja aplikacja nie zapisała jeszcze zwróconego identyfikatora zadania. Niektóre asynchroniczne przepływy pracy obrazów opakowują synchroniczne generowanie u źródła, więc samo zgłoszenie nadal może wymagać czasu.
Ładunki sukcesu i niepowodzenia
Powiadomienie o sukcesie zawiera publiczny identyfikator zadania i uwierzytelniony link do wideo:
{
"id":"evt_example",
"type":"task.completed",
"api_version":"2026-10-03",
"created_at":1791014400,
"data":{
"task_id":"task_example",
"model":"seedance-2.5",
"kind":"video",
"status":"completed",
"client_reference_id":"order_123",
"completed_at":1791014400,
"task_url":"https://apimaster.ai/v1/videos/task_example",
"result":{
"outputs":[{
"output_id":"0",
"type":"video",
"url":"https://apimaster.ai/v1/videos/task_example/content",
"authentication":"bearer",
"expires_at":null
}]
},
"error":null
}
}
Niepowodzenie używa tej samej koperty z type: "task.failed", data.status: "failed", data.result: null oraz obiektem błędu:
{
"code":"generation_failed",
"message":"The generation task failed. Query the task for details."
}
Zarówno niepowodzenia potwierdzone przez dostawcę, jak i przekroczenia czasu zadań bramy mogą generować zdarzenia niepowodzenia. Żądanie utworzenia odrzucone przed zaakceptowaniem zadania nie generuje zdarzenia zadania. Niepowodzenie dostarczenia powiadomienia nie zmienia statusu generowania ani nie uruchamia ponownego generowania. Zdarzenia nie potwierdzają zakończenia rozliczeń finansowych.
Dla obrazów, kind to image, a outputs zawiera wszystkie dostępne wyjścia obrazów. Zdarzenia zadań potomnych Midjourney zawierają batch_id; możesz dodatkowo zasubskrybować batch.completed, aby otrzymać jedno zbiorcze podsumowanie po zakończeniu wszystkich zadań potomnych. Jego status to completed, partial_failure lub failed, z liczbami w data.summary. Zakończenie zbiorcze nie zawsze oznacza, że każde zadanie potomne zakończyło się sukcesem.
Pobieraj adresy URL wyników za pomocą klucza API należącego do konta zadania. Zapisz wygenerowane media niezwłocznie. expires_at: null oznacza, że nie podano gwarantowanego czasu wygaśnięcia, a nie trwałe przechowywanie; późniejsze pobranie może zwrócić HTTP 410. Odtworzenie zdarzenia nie przedłuża dostępności mediów.
Uwierzytelnianie callbacków i natychmiastowe potwierdzanie
Każde żądanie POST zawiera:
X-APIMaster-Event-ID: evt_example
X-APIMaster-Delivery-ID: dlv_example
X-APIMaster-Timestamp: 1791014400
X-APIMaster-Signature: v1=<hex-hmac>,kid=<key-id>
Zweryfikuj HMAC-SHA256 na podstawie znacznika czasu, dosłownej kropki i surowych bajtów treści żądania, używając sekretu podpisywania punktu końcowego. Użyj porównania stałoczasowego, dopuść maksymalnie pięć minut przesunięcia zegara i sprawdź, czy nagłówek Event-ID zgadza się z ID w treści. Ponowne próby zachowują to samo ID zdarzenia i treść, ale otrzymują nowe ID dostarczenia, znacznik czasu i podpis.
Poniższy odbiornik w Pythonie używa Flaska i SQLite. Atomowo zapisuje zdarzenie przed jego potwierdzeniem. Twój worker aplikacji powinien osobno konsumować zapisane wiersze, pobierać pliki i uruchamiać logikę biznesową.
import hashlib, hmac, json, os, sqlite3, time
from flask import Flask, request, jsonify, abort
app = Flask(__name__)
# During key rotation, configure both active and previous kid/secret pairs.
SECRETS = json.loads(os.environ["APIMASTER_WEBHOOK_SECRETS_JSON"])
DB_PATH = os.environ.get("WEBHOOK_DB_PATH", "webhook-events.sqlite3")
with sqlite3.connect(DB_PATH) as db:
db.execute("CREATE TABLE IF NOT EXISTS events (id TEXT PRIMARY KEY, body BLOB NOT NULL)")
@app.post("/webhooks/apimaster")
def receive():
raw = request.get_data()
try:
timestamp = request.headers["X-APIMaster-Timestamp"]
if abs(time.time() - int(timestamp)) > 300:
abort(401)
fields = dict(part.split("=", 1) for part in
request.headers["X-APIMaster-Signature"].split(","))
secret = SECRETS[fields["kid"]]
expected = hmac.new(secret.encode(), timestamp.encode() + b"." + raw,
hashlib.sha256).hexdigest()
if not hmac.compare_digest(expected, fields["v1"]):
abort(401)
event = json.loads(raw)
if event["id"] != request.headers["X-APIMaster-Event-ID"]:
abort(401)
except (KeyError, ValueError, TypeError):
abort(401)
if event["type"] == "webhook.endpoint_verification":
return jsonify(challenge=event["data"]["challenge"])
with sqlite3.connect(DB_PATH) as db:
db.execute("INSERT OR IGNORE INTO events(id, body) VALUES (?, ?)",
(event["id"], raw))
return "", 204
Zwróć dowolny status 2xx w ciągu 10 sekund dla zdarzeń generowania. Potwierdź po trwałym zapisaniu, bez oczekiwania na pobranie mediów. Dostarczenie jest co najmniej raz: możliwe są zdublowane zdarzenia, szczególnie jeśli potwierdzenie zostanie utracone, więc deduplikuj za pomocą id. Nie ma gwarancji kolejności między zadaniami.
Ponowne próby, historia dostarczeń i odtwarzanie
APIMaster ponawia próby w przypadku awarii sieci, przekroczeń czasu potwierdzenia i odpowiedzi innych niż 2xx przez okres do 72 godzin od utworzenia zdarzenia. Początkowe opóźnienia wynoszą 1, 2, 5, 15 i 30 minut, następnie 1, 2, 4 i 8 godzin, a później 12-godzinne interwały, z losowym odchyleniem (jitter) do 20%. Prawidłowy Retry-After dla statusów 429/503 jest respektowany w oknie ponawiania. Przekierowania nie są śledzone. HTTP 410 wstrzymuje punkt końcowy; inne odpowiedzi 4xx są ponawiane, aby umożliwić poprawki konfiguracyjne.
curl --fail-with-body "https://apimaster.ai/v1/webhook-events?task_id=task_example" \
-H "Authorization: Bearer YOUR_API_KEY"
curl --fail-with-body "https://apimaster.ai/v1/webhook-events/evt_example/deliveries" \
-H "Authorization: Bearer YOUR_API_KEY"
curl --fail-with-body -X POST "https://apimaster.ai/v1/webhook-events/evt_example/redeliver" \
-H "Authorization: Bearer YOUR_API_KEY"
Statusy obejmują pending, in_flight, retrying, delivered, paused i exhausted. Rekordy zdarzeń i prób są przechowywane przez 30 dni. Odtwarzanie zachowuje oryginalne ID zdarzenia i ładunek oraz otwiera nowe 72-godzinne okno dostarczenia; nie generuje ponownie mediów ani nie pobiera ponownie opłaty. Dozwolone jest do pięciu ręcznych odtworzeń na zdarzenie na dzień UTC. Zdarzenie aktualnie wydzierżawione do dostarczenia nie może być odtworzone, dopóki ta próba się nie zakończy lub jej dzierżawa nie wygaśnie.
Wstrzymaj lub wznowij punkt końcowy za pomocą PATCH /v1/webhook-endpoints/{id} i {"enabled":false} lub {"enabled":true}. Wznowienie kontynuuje wstrzymane zdarzenia, których oryginalny termin nie minął. Obróć sekrety za pomocą POST /v1/webhook-endpoints/{id}/rotate-secret; zapisz nowy sekret i kid, i zachowaj poprzednią parę przez zwrócony 24-godzinny okres przejściowy.
Rezerwowe odpytywanie (Polling)
Dla zadań, które nie otrzymały terminalnego zdarzenia, odpytuj /v1/videos/{task_id} lub udokumentowane zapytanie zadania obrazu modelu co 60–120 sekund. Użyj API zadań jako źródła prawdy i sprawdź historię dostarczeń, jeśli generowanie zostało zakończone, ale brakuje powiadomienia. Brak webhooka nie jest powodem do ponownego wysłania płatnego żądania generowania. Długotrwała niedostępność punktu końcowego może wyczerpać automatyczne ponawianie; przywróć odbiornik i odtwórz zachowane zdarzenia.
