Devoluciones de llamada
Reciba y verifique de forma segura las entregas de devoluciones de llamada de Tasks.
Usa devoluciones de llamada para recibir eventos del ciclo de vida de una Task en un endpoint HTTPS público. Verifica cada devolución de llamada antes de procesar su cuerpo JSON para que solo las entregas firmadas para tu cuenta puedan cambiar el estado de la aplicación.
Configurar una URL de devolución de llamada
Agrega una callback_url HTTPS pública cuando crees una tarea. El cuerpo del evento
y los estados del ciclo de vida dependen del endpoint; consulta la Referencia de la API
de ese endpoint para conocer sus cargas útiles de devolución de llamada.
{
"model": "flux-2-pro-text-to-image",
"prompt": "A product photograph on a clean studio background",
"callback_url": "https://your-domain.com/webhooks/runapi"
}
Crear un Callback Secret
Siga la Guía de Autenticación para iniciar sesión, luego abra Claves de API y cree una clave secreta de devolución de llamada para la cuenta que crea la tarea. Guarde el valor en un administrador de secretos y hágalo disponible solamente para su receptor de devoluciones de llamada. No es una clave de API y nunca debe enviarse en una solicitud de tarea.
El secreto firma las devoluciones de llamada para esa cuenta. Rotarlo cambia la firma de las entregas posteriores, por lo que debes actualizar todos los receptores de devoluciones de llamada de inmediato y mantener ambos valores disponibles solo el tiempo suficiente para gestionar las entregas en curso.
Verificar una firma de devolución de llamada
Cada devolución de llamada es un HTTP POST con Content-Type: application/json.
RunAPI no agrega un encabezado Authorization a esta solicitud. Verifique
estos encabezados antes de deserializar el cuerpo:
X-Callback-Id
Identificador único para este intento de entrega.
X-Callback-Timestamp
Marca de tiempo Unix en segundos en el momento en que se firmó la entrega.
X-Callback-Signature
Firma HMAC-SHA-256 codificada en Base64.
Construya el valor firmado exactamente de la siguiente manera, utilizando los bytes del cuerpo de la solicitud sin modificar:
X-Callback-Id + "." + X-Callback-Timestamp + "." + raw request body
Decodifique en Base64 el Callback Secret, calcule HMAC-SHA-256 sobre ese
valor, codifique el resultado en Base64 y compárelo con
X-Callback-Signature usando una comparación segura en tiempo. No analice ni
vuelva a serializar el JSON antes de 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);
}
Pase la cadena del cuerpo de la solicitud sin procesar del framework a rawBody; no llame
a JSON.stringify sobre datos ya analizados.
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)
Pase la cadena exacta del cuerpo de la solicitud sin procesar recibida por su framework HTTP
como raw_body.
Procesar entregas de forma segura
- Devuelva una respuesta
2xxsolo después de que la devolución de llamada haya sido aceptada para su procesamiento. Tras una respuesta que no sea2xxo un error de transporte, se intenta la entrega hasta 10 veces. - Responda en un plazo de 15 segundos. Encole el trabajo más lento después de la verificación en lugar de bloquear la respuesta HTTP.
- Rechace las devoluciones de llamada con encabezados de firma ausentes, una firma no válida o una marca de tiempo fuera de la ventana de tolerancia que defina su receptor.
Solución de problemas de verificación
- Discrepancia de firma: confirma que el secreto de devolución de llamada pertenece a la misma cuenta que la Tarea, decodifícalo con Base64 y firma el cuerpo original en lugar del JSON analizado.
- Encabezados de firma ausentes: crea un secreto de devolución de llamada antes de depender de las devoluciones de llamada para cambios de estado.
- Marca de tiempo rechazada: sincroniza el reloj del receptor y usa una tolerancia adecuada para tu despliegue.
Para obtener orientación sobre la configuración y el ciclo de vida, vuelva al Inicio rápido de la API de Task.