Callback
Ricevi e verifica in modo sicuro le consegne dei callback dei Task.
Usa le callback per ricevere gli eventi del ciclo di vita del Task presso un endpoint HTTPS pubblico. Verifica ogni callback prima di elaborarne il corpo JSON affinché solo le consegne firmate per il tuo account possano modificare lo stato dell’applicazione.
Configura un URL di callback
Aggiungi un callback_url HTTPS pubblico quando crei un Task. Il corpo dell’evento
e gli stati del ciclo di vita dipendono dall’endpoint; consulta il Riferimento API di quell’endpoint
per i payload di callback.
{
"model": "flux-2-pro-text-to-image",
"prompt": "A product photograph on a clean studio background",
"callback_url": "https://your-domain.com/webhooks/runapi"
}
Creare un Callback Secret
Segui la Guida all’Autenticazione per accedere, therefore apri Chiavi API e crea un Segreto Callback per l’account che crea il Task. Conserva il valore in un gestore di segreti e rendilo disponibile solo al tuo ricevitore di callback. Non è una Chiave API e non deve mai essere inviato in una richiesta Task.
Il segreto firma i callback per quell’account. La sua rotazione cambia la firma per le consegne successive, quindi aggiorna immediatamente ogni ricevitore di callback e tieni entrambi i valori disponibili solo per il tempo necessario a gestire le consegne in corso.
Verifica la firma di una Callback
Ogni callback è un HTTP POST con Content-Type: application/json.
RunAPI non aggiunge un’intestazione Authorization a questa richiesta. Verifica
queste intestazioni prima di deserializzare il corpo:
X-Callback-Id
Identificatore univoco per questo tentativo di consegna.
X-Callback-Timestamp
Timestamp Unix in secondi di quando la consegna è stata firmata.
X-Callback-Signature
Firma HMAC-SHA-256 codificata in Base64.
Costruisci il valore firmato esattamente come segue, utilizzando i byte del corpo della richiesta non modificati:
X-Callback-Id + "." + X-Callback-Timestamp + "." + raw request body
Decodifica in Base64 il Callback Secret, calcola HMAC-SHA-256 su quel
valore, codifica in Base64 il risultato e confrontalo con
X-Callback-Signature usando un confronto a tempo costante. Non analizzare e
ri-serializzare il JSON prima di verificarlo.
JavaScript
import { createHmac, timingSafeEqual } from "node:crypto";
export function verifyCallback({headers, rawBody, callbackSecret}) {
const callbackId = headers["x-callback-id"];
const timestamp = Number(headers["x-callback-timestamp"]);
const signature = headers["x-callback-signature"];
if (!callbackId || !signature || !Number.isSafeInteger(timestamp)) return false;
if (Math.abs(Date.now() / 1000 - timestamp) > 300) return false;
const signedContent = `${callbackId}.${timestamp}.${rawBody}`;
const expected = createHmac("sha256", Buffer.from(callbackSecret, "base64"))
.update(signedContent, "utf8")
.digest();
const received = Buffer.from(signature, "base64");
return expected.length === received.length && timingSafeEqual(expected, received);
}
Passa la stringa grezza del corpo della richiesta del framework a rawBody; non chiamare
JSON.stringify sui dati già analizzati.
Python
import base64
import hashlib
import hmac
import time
def verify_callback(headers, raw_body, callback_secret):
callback_id = headers.get("X-Callback-Id")
timestamp = headers.get("X-Callback-Timestamp")
signature = headers.get("X-Callback-Signature")
if not callback_id or not timestamp or not signature:
return False
try:
timestamp = int(timestamp)
secret = base64.b64decode(callback_secret, validate=True)
received = base64.b64decode(signature, validate=True)
except (ValueError, TypeError):
return False
if abs(time.time() - timestamp) > 300:
return False
signed_content = f"{callback_id}.{timestamp}.{raw_body}".encode("utf-8")
expected = hmac.new(secret, signed_content, hashlib.sha256).digest()
return hmac.compare_digest(expected, received)
Passa l’esatta stringa grezza del corpo della richiesta ricevuta dal tuo framework HTTP
come raw_body.
Gestire le consegne in modo sicuro
- Restituisci una risposta
2xxsolo dopo che la callback è stata accettata per l’elaborazione. In caso di risposta non2xxo di errore di trasporto, la consegna viene ritentata fino a 10 volte. - Rispondi entro 15 secondi. Accoda il lavoro più lento dopo la verifica anziché bloccare la risposta HTTP.
- Rifiuta le callback prive di intestazioni di firma, con firma non valida o con un timestamp al di fuori della finestra di tolleranza definita dal tuo ricevitore.
Risoluzione dei problemi di verifica
- Mancata corrispondenza della firma: conferma che il Callback Secret appartenga allo stesso account del Task, decodificalo con Base64 e firma il corpo originale anziché il JSON analizzato.
- Intestazioni di firma mancanti: crea un Callback Secret prima di affidarti ai callback per i cambiamenti di stato.
- Timestamp rifiutato: sincronizza l’orologio del ricevitore e usa una tolleranza appropriata per il tuo deployment.
Per le istruzioni di configurazione e ciclo di vita, torna alla Guida introduttiva all’API Task.