↓
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 11 de mayo de 2026

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 periódica mediante GET /api/v1/generations/{taskId} sigue disponible. Los webhooks añaden avisos firmados para sistemas de producción que prefieren recibir eventos.

Permiso requerido

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

webhooks:manage

Las claves nuevas creadas en Ajustes incluyen este permiso de forma predeterminada.

Crear un destino

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 a la ruta de rotación y actualiza el receptor.

Reglas de URL

Las URL de destino deben usar HTTPS. Rivya rechaza direcciones con credenciales, fragmentos, nombres localhost, redes locales, rangos de IP privadas, direcciones de bucle invertido 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

Las cargas de los webhooks usan el mismo serializador público de generación que la ruta 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 con el secreto de firma del destino

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 destino. 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_..."

Muestra los intentos de entrega de un destino:

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 la consulta periódica como respaldo para la conciliación.

Páginas relacionadas