APIMaster.ai

APIMaster Webhook per Attività Asincrone

Ricevi notifiche firmate di completamento e fallimento per Seedance, video e attività asincrone di immagini, con ritentativi, cronologia di consegna e polling di riserva.

Webhook per attività asincrone di APIMaster

Utilizza i webhook come meccanismo di notifica principale per la generazione asincrona e mantieni il polling come riserva. APIMaster invia una richiesta HTTPS POST firmata quando un'attività tracciata viene completata o fallisce. Le notifiche sono indipendenti dal provider di generazione e utilizzano il tuo ID attività APIMaster.

Modelli ed endpoint supportati

Seedance include tutti e quattro i modelli: seedance-2.0, seedance-2.5, seedance-2.0-fast e seedance-2.0-mini. Utilizza POST /v1/videos/generations o il compatibile POST /v1/video/generations.

Le notifiche per attività video supportano anche MiniMax-H3, Kling Omni / Motion Control, Grok Imagine Video e Sora. I flussi di lavoro supportati per immagini GPT 2 / 2.5 e Gemini utilizzano /v1/images/generations/async o i /v1/images/edits/async supportati; Midjourney v8.2 / Niji 7 utilizzano /v1/midjourney/generations. La disponibilità delle route e i parametri di generazione seguono comunque la guida di ciascun modello. La generazione sincrona di Seedream e Grok immagini, lo streaming di chat e la revisione degli asset Seedance non fanno parte di questo contratto di webhook di generazione.

Controlla GET /v1/webhook-capabilities?model=seedance-2.0-fast per l'idoneità del modello. Utilizza un endpoint di invio asincrono supportato; l'idoneità non significa che ogni operazione su immagini o ogni alias di modello supporti la generazione asincrona.

Registra e verifica un endpoint

Utilizza la tua chiave API in Authorization: Bearer YOUR_API_KEY. Una chiave API può gestire endpoint ed eventi appartenenti al suo account. Conservala sul tuo server.

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"}'

La risposta contiene endpoint.id, endpoint.key_id e signing_secret. Conserva il segreto di firma in modo sicuro: viene restituito una sola volta. È separato dalla tua chiave API e non può autorizzare la generazione o i download. L'URL deve essere un endpoint HTTPS pubblicamente raggiungibile sulla porta 443. Gli indirizzi privati e i reindirizzamenti vengono rifiutati. Sono consentiti fino a 20 endpoint per account; gli URL sono immutabili, quindi crea e verifica un nuovo endpoint quando cambi la destinazione.

Dopo aver configurato il tuo ricevitore, verifica la proprietà:

curl --fail-with-body -X POST "https://apimaster.ai/v1/webhook-endpoints/whep_example/verify" \
  -H "Authorization: Bearer YOUR_API_KEY"

APIMaster invia un evento firmato webhook.endpoint_verification contenente data.challenge. Restituisci HTTP 200 con {"challenge":"THE_RECEIVED_CHALLENGE"} entro 10 secondi. Una richiesta di generazione che fa riferimento a un endpoint non verificato, in pausa o di un altro account viene rifiutata prima dell'invio.

Il timeout totale della richiesta HTTP è di 10 secondi, inclusi DNS, connessione e TLS. Gli header di risposta devono arrivare entro 8 secondi dall’invio. Salvare l’evento in modo persistente e confermare subito la ricezione.

Invia un'attività con notifiche

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"
  }'

Sostituisci l'ID del modello con uno qualsiasi dei quattro ID Seedance mantenendo i suoi parametri supportati. Salva l'ID dell'attività dalla normale risposta di creazione. client_reference_id è un riferimento aziendale opzionale di al massimo 128 byte; non è una chiave di idempotenza per l'invio. Non combinare notifications con i parametri legacy del provider webhook o callback_url.

Per le modifiche di immagini multipart supportate, invia notifications come campo modulo stringa JSON e client_reference_id come campo modulo separato:

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"

Non c'è un endpoint predefinito a livello di account in questa versione: fai riferimento a un endpoint in ogni richiesta di attività. I webhook potrebbero arrivare prima della risposta del tuo invio. Conservali anche se la tua applicazione non ha ancora salvato l'ID dell'attività restituito. Alcuni flussi di lavoro asincroni per immagini racchiudono una generazione sincrona upstream, quindi l'invio stesso può comunque richiedere tempo.

Payload di successo e fallimento

Una notifica di successo contiene l'ID pubblico dell'attività e un link video autenticato:

{
  "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
  }
}

Il fallimento utilizza la stessa busta con type: "task.failed", data.status: "failed", data.result: null e un oggetto di errore:

{
  "code":"generation_failed",
  "message":"The generation task failed. Query the task for details."
}

Sia i fallimenti confermati dal provider che i timeout delle attività del gateway possono generare eventi di fallimento. Una richiesta di creazione rifiutata prima che un'attività venga accettata non genera un evento di attività. Il fallimento della consegna della notifica non cambia lo stato di generazione né riavvia la generazione. Gli eventi non confermano che la riconciliazione di fatturazione sia terminata.

Per le immagini, kind è image e outputs contiene tutte le immagini di output disponibili. Gli eventi delle attività figlio di Midjourney includono batch_id; puoi inoltre iscriverti a batch.completed per ricevere un riepilogo del batch dopo che tutti i figli sono terminati. Il suo stato è completed, partial_failure o failed, con i conteggi in data.summary. Il completamento del batch non significa sempre che ogni figlio abbia avuto successo.

Scarica gli URL di output con una chiave API appartenente all'account dell'attività. Salva i media generati prontamente. expires_at: null significa che non viene fornito un tempo di scadenza garantito, non uno storage permanente; un download successivo può restituire HTTP 410. Riprodurre un evento non estende la disponibilità dei media.

Autentica i callback e conferma tempestivamente

Ogni POST contiene:

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>

Verifica HMAC-SHA256 sul timestamp, un punto letterale e i byte grezzi del corpo della richiesta utilizzando il segreto di firma dell'endpoint. Utilizza un confronto a tempo costante, consenti al massimo cinque minuti di scostamento dell'orologio e controlla che l'header Event-ID corrisponda all'ID nel corpo. I tentativi di ritrasmissione mantengono lo stesso ID evento e corpo ma ricevono un nuovo ID di consegna, timestamp e firma.

Il seguente ricevitore Python utilizza Flask e SQLite. Persiste un evento in modo atomico prima di confermarlo. Il tuo worker dell'applicazione dovrebbe consumare le righe salvate, scaricare i file ed eseguire la logica di business separatamente.

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

Restituisci qualsiasi stato 2xx entro 10 secondi per gli eventi di generazione. Conferma dopo l'archiviazione durevole, senza attendere il download dei media. La consegna è almeno una volta: sono possibili eventi duplicati, specialmente se una conferma viene persa, quindi deduplica per id. Non c'è alcuna garanzia di ordinamento tra i task.

Tentativi di ritrasmissione, cronologia delle consegne e replay

APIMaster ritenta in caso di errori di rete, timeout di conferma e risposte non 2xx per un massimo di 72 ore dalla creazione dell'evento. I ritardi iniziali sono di 1, 2, 5, 15 e 30 minuti, poi 1, 2, 4 e 8 ore, seguiti da intervalli di 12 ore, con un jitter fino al 20%. Un valido Retry-After su 429/503 viene rispettato entro la finestra di ritrasmissione. I reindirizzamenti non vengono seguiti. HTTP 410 mette in pausa l'endpoint; altre risposte 4xx vengono ritentate per consentire correzioni di configurazione.

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"

Gli stati includono pending, in_flight, retrying, delivered, paused e exhausted. I record degli eventi e dei tentativi vengono conservati per 30 giorni. Il replay preserva l'ID evento originale e il payload e apre una nuova finestra di consegna di 72 ore; non rigenera i media né addebita nuovamente. Sono consentiti fino a cinque replay manuali per evento per giorno UTC. Un evento attualmente in leasing per la consegna non può essere riprodotto fino a quando quel tentativo non termina o il suo leasing scade.

Metti in pausa o riprendi un endpoint con PATCH /v1/webhook-endpoints/{id} e {"enabled":false} o {"enabled":true}. La ripresa continua gli eventi in pausa la cui scadenza originale non è ancora passata. Ruota i segreti con POST /v1/webhook-endpoints/{id}/rotate-secret; salva il nuovo segreto e kid, e conserva la coppia precedente per il periodo di transizione di 24 ore restituito.

Fallback di polling

Per i task senza un evento terminale ricevuto, interroga /v1/videos/{task_id} o la query image-task documentata del modello ogni 60–120 secondi. Utilizza l'API dei task come fonte di verità e controlla la cronologia delle consegne se la generazione è terminata ma la notifica manca. Un webhook mancante non è un motivo per inviare nuovamente una richiesta di generazione a pagamento. Un'interruzione prolungata dell'endpoint può esaurire i tentativi automatici; ripristina il ricevitore e riproduci gli eventi conservati.