Documentación de Rivya AI

Webhooks de API

Crea endpoints de webhook firmados para la API de Rivya, verifica firmas de entrega, revisa intentos de entrega y envía eventos de prueba seguros.

Última revisión el 2026/05/11

Usa webhooks de API cuando tu integración necesite que Rivya notifique a tu servidor después de que una generación de Public API llegue a un estado terminal.

La consulta por polling con GET /api/v1/generations/{taskId} sigue disponible. Los webhooks añaden callbacks firmados para sistemas de producción que prefieren recibir eventos.

Scope requerido

La gestión de webhooks requiere una clave de API con:

webhooks:manage

Las claves nuevas creadas en Settings incluyen este scope por defecto.

Crear endpoint

POST /api/v1/webhooks
curl https://rivya.ai/api/v1/webhooks \
  -H "Authorization: Bearer rvya_sk_..." \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Production webhook",
    "url": "https://example.com/rivya/webhook",
    "event_types": ["generation.succeeded", "generation.failed"]
  }'

La respuesta incluye signing_secret solo una vez:

{
  "id": "whend_...",
  "object": "webhook_endpoint",
  "name": "Production webhook",
  "url": "https://example.com/rivya/webhook",
  "event_types": ["generation.succeeded", "generation.failed"],
  "status": "active",
  "secret_preview": "whsec_12...abc123",
  "signing_secret": "whsec_...",
  "last_success_at": null,
  "last_failure_at": null,
  "failure_count": 0,
  "created_at": "2026-05-11T00:00:00.000Z",
  "updated_at": "2026-05-11T00:00:00.000Z",
  "disabled_at": null,
  "revoked_at": null
}

Guarda el secreto completo en tu servidor. Si lo pierdes, llama al endpoint de rotación y actualiza tu receptor.

Reglas de URL

Las URL de endpoint deben usar HTTPS. Rivya rechaza URL con credenciales, fragmentos, nombres localhost, direcciones de red local, rangos de IP privadas, direcciones loopback y direcciones reservadas.

Rivya siempre envía:

  • POST
  • Content-Type: application/json
  • sin headers de solicitud personalizados controlados por el usuario
  • sin seguimiento automático de redirecciones
  • un timeout de entrega corto

Eventos

Tipos de evento actuales:

  • generation.succeeded
  • generation.failed

Los payloads de webhook usan el mismo serializador público de generación que el endpoint de estado.

{
  "id": "evt_...",
  "type": "generation.succeeded",
  "api_version": "2026-05-11",
  "created_at": "2026-05-11T00:00:00.000Z",
  "data": {
    "generation": {
      "id": "task_public_id",
      "status": "succeeded",
      "model": "z-image",
      "reserved_credits": 1,
      "final_credits": 1,
      "created_at": "2026-05-11T00:00:00.000Z",
      "updated_at": "2026-05-11T00:01:00.000Z",
      "result": {
        "primary_url": "https://...",
        "urls": ["https://..."]
      },
      "error": null
    }
  }
}

Headers de entrega

Cada entrega incluye:

Rivya-Webhook-Id: evt_...
Rivya-Webhook-Timestamp: 1778467200
Rivya-Webhook-Signature: v1=<hex-hmac-sha256>
Rivya-Webhook-Attempt: 1
Rivya-Webhook-Endpoint-Id: whend_...
Rivya-Request-Id: req_...

Entrada de firma:

${timestamp}.${rawBody}

Algoritmo:

HMAC-SHA256 with the endpoint signing secret

Rechaza solicitudes con timestamps obsoletos. Una tolerancia de cinco minutos es un valor práctico por defecto.

Verificación en JavaScript

import crypto from "node:crypto";

function verifyRivyaWebhook({ rawBody, headers, signingSecret }) {
  const timestamp = headers["rivya-webhook-timestamp"];
  const signature = headers["rivya-webhook-signature"] || "";
  const actual = signature.split(",").find((part) => part.startsWith("v1="))?.slice(3);
  const expected = crypto
    .createHmac("sha256", signingSecret)
    .update(`${timestamp}.${rawBody}`)
    .digest("hex");

  if (!actual) return false;
  return crypto.timingSafeEqual(Buffer.from(actual, "hex"), Buffer.from(expected, "hex"));
}

Verificación en Python

import hmac
import hashlib

def verify_rivya_webhook(raw_body: str, headers: dict, signing_secret: str) -> bool:
    timestamp = headers.get("rivya-webhook-timestamp", "")
    signature = headers.get("rivya-webhook-signature", "")
    actual = next((part[3:] for part in signature.split(",") if part.startswith("v1=")), "")
    expected = hmac.new(
        signing_secret.encode(),
        f"{timestamp}.{raw_body}".encode(),
        hashlib.sha256,
    ).hexdigest()
    return bool(actual) and hmac.compare_digest(actual, expected)

Gestionar endpoints

GET /api/v1/webhooks
GET /api/v1/webhooks/{endpointId}
PATCH /api/v1/webhooks/{endpointId}
DELETE /api/v1/webhooks/{endpointId}
POST /api/v1/webhooks/{endpointId}/rotate-secret
curl https://rivya.ai/api/v1/webhooks \
  -H "Authorization: Bearer rvya_sk_..."

curl https://rivya.ai/api/v1/webhooks/whend_... \
  -H "Authorization: Bearer rvya_sk_..."

curl -X PATCH https://rivya.ai/api/v1/webhooks/whend_... \
  -H "Authorization: Bearer rvya_sk_..." \
  -H "Content-Type: application/json" \
  -d '{"status":"disabled"}'

curl -X POST https://rivya.ai/api/v1/webhooks/whend_.../rotate-secret \
  -H "Authorization: Bearer rvya_sk_..."

DELETE /api/v1/webhooks/{endpointId} desactiva el endpoint. No elimina el historial de entregas.

Registros de entrega

Lista eventos recientes:

GET /api/v1/webhook-events
curl https://rivya.ai/api/v1/webhook-events \
  -H "Authorization: Bearer rvya_sk_..."

Lista los intentos de entrega de un endpoint:

GET /api/v1/webhooks/{endpointId}/deliveries
curl https://rivya.ai/api/v1/webhooks/whend_.../deliveries \
  -H "Authorization: Bearer rvya_sk_..."

Los registros de entrega incluyen estado, estado HTTP, número de intento, request id, duración, fragmento truncado de la respuesta y campos de error públicos.

Evento de prueba

Envía un payload de prueba seguro:

POST /api/v1/webhooks/{endpointId}/test
curl -X POST https://rivya.ai/api/v1/webhooks/whend_.../test \
  -H "Authorization: Bearer rvya_sk_..."

El evento de prueba usa webhook.test. No crea una tarea de generación, no consume créditos y no incluye una URL de resultado real.

Política de reintentos

Rivya trata HTTP 2xx como éxito.

Los fallos incluyen errores de red, timeout, respuestas de redirección y respuestas que no son 2xx. Rivya reintenta hasta cinco veces:

  • inmediatamente
  • después de 1 minuto
  • después de 5 minutos
  • después de 30 minutos
  • después de 2 horas

Después del intento final, el evento se marca como failed.

Los fallos de entrega de webhook no cambian el estado de la generación, los créditos, los reembolsos ni el historial de la tarea.

Checklist de seguridad

  • Verifica la firma HMAC antes de procesar la lógica de negocio.
  • Rechaza timestamps obsoletos.
  • Trata los eventos de prueba por separado de los eventos de generación.
  • No registres secretos de firma completos en logs.
  • Devuelve 2xx solo después de que tu receptor haya aceptado el evento.
  • Mantén el polling como respaldo para reconciliación.

Páginas relacionadas

Tabla de contenido