CreaVibeAPIVolver a CreaVibe

Webhooks

En lugar de consultar un trabajo de IA hasta que termina, puedes indicar una webhook_url y CreaVibe te avisará con su resultado.

Cómo se usa

Añade webhook_url al crear el trabajo (POST /jobs). Debe ser una URL https pública. Cuando el trabajo termine, CreaVibe enviará un POST a esa URL con el trabajo completo, el mismo que devuelve Consultar un trabajo:

POST a tu webhook_url · cabeceras
Content-Type: application/json
webhook-id: 974c1661-3528-4099-9406-9688f1248f78.succeeded
webhook-timestamp: 1791799880
webhook-signature: v1,<HMAC-SHA256 en base64>
POST a tu webhook_url · cuerpo
{
  "type": "job.succeeded",
  "timestamp": 1791799880,
  "data": {
    "id": "974c1661-3528-4099-9406-9688f1248f78",
    "type": "generate_svg",
    "status": "succeeded",
    "style": null,
    "asset": {
      "id": "087f7237-8b00-4fd1-9e08-9736b2b754f7",
      "url": "https://creavibe.app/media/recursos/017dfef2-eaf5-429a-86f3-307b8bf36189/ef7523e1cdc34bb98d3cde4b938d311d.svg",
      "thumbnail_url": "https://creavibe.app/media/recursos/017dfef2-eaf5-429a-86f3-307b8bf36189/ef7523e1cdc34bb98d3cde4b938d311d.svg",
      "type": "svg",
      "source": "generated",
      "name": "Coffee shop icons cup bean croissant",
      "font_family": null,
      "width": null,
      "height": null,
      "size_bytes": 3575,
      "created_at": "2026-10-12T10:11:10.932Z"
    },
    "reply": null,
    "error": null,
    "credits_remaining": 15,
    "webhook_url": null,
    "created_at": "2026-10-12T10:10:32.074Z",
    "updated_at": "2026-10-12T10:10:52.996Z"
  }
}

Eventos

typeCuándo
job.succeededEl trabajo terminó: el resultado está en data.asset.
job.failedEl trabajo falló: el motivo está en data.error.code y los créditos se han devuelto.

Verificar la firma

Cada aviso va firmado según el estándar Standard Webhooks: un HMAC-SHA256 de {webhook-id}.{webhook-timestamp}.{cuerpo} con tu secreto. Comprueba la firma antes de fiarte del contenido y rechaza los avisos de hace más de 5 minutos.

Tu secreto (whsec_…) está en el menú de tu cuenta, en API → MCP y Webhook (entra en CreaVibe); desde ahí también puedes regenerarlo.

import crypto from 'node:crypto';

// secret: el de tu cuenta (whsec_…); body: el cuerpo tal cual llegó (texto, sin volver a serializarlo)
function verify(secret, headers, body) {
  const key = Buffer.from(secret.replace(/^whsec_/, ''), 'base64');
  const signed = `${headers['webhook-id']}.${headers['webhook-timestamp']}.${body}`;
  const expected = 'v1,' + crypto.createHmac('sha256', key).update(signed).digest('base64');
  const fresh = Math.abs(Date.now() / 1000 - Number(headers['webhook-timestamp'])) < 300;
  return fresh && headers['webhook-signature'].split(' ').some(sig =>
    sig.length === expected.length && crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected)));
}
import base64, hashlib, hmac, time

# secret: el de tu cuenta (whsec_…); body: el cuerpo tal cual llegó (bytes decodificados, sin volver a serializarlo)
def verify(secret, headers, body):
    key = base64.b64decode(secret.removeprefix("whsec_"))
    signed = f"{headers['webhook-id']}.{headers['webhook-timestamp']}.{body}".encode()
    expected = "v1," + base64.b64encode(hmac.new(key, signed, hashlib.sha256).digest()).decode()
    fresh = abs(time.time() - int(headers["webhook-timestamp"])) < 300
    return fresh and any(hmac.compare_digest(sig, expected) for sig in headers["webhook-signature"].split())

Entrega y reintentos

  • Responde con cualquier código 2xx en menos de 10 segundos; haz el trabajo pesado después.
  • Si no responde o responde otra cosa, se reintenta hasta 6 veces con esperas crecientes (de 1 minuto a unas 17 horas).
  • Un mismo aviso puede llegar más de una vez: usa webhook-id para no procesarlo dos veces.
  • No se siguen redirecciones.