Webhooks
Empuja completions de jobs por HTTP a tu endpoint — en vez de hacer polling.
Los webhooks son la vía push de la API de Rankion: en vez de montar un polling loop tras cada 202 Accepted, registras un endpoint HTTPS y Rankion entrega los completions de jobs por POST apenas terminan. Ideal para integraciones con Zapier/Make, backends propios o notificaciones a Slack. Los webhooks son complementarios a Automation (pipelines internas) — abandonan la plataforma.
Estado: los webhooks outbound están en planificación. Actualmente solo existe un webhook inbound para review sources externas:
POST /api/v1/webhooks/reviews/{source}(basado en key, sin Sanctum, ver Review Sources). Una UI general bajo/settings/webhookscon gestión de subscripciones y firma HMAC todavía no está desplegada. La lista de eventos, envoltorio de payload y verificación HMAC descritos abajo son la convención prevista — pueden cambiar antes del release. Para updates inmediatos de status: usa polling REST contra el endpoint detail correspondiente.
Configuración (UI) — prevista
Los endpoints de webhook se crean (tras el release) en el frontend bajo /settings/webhooks:
- Indica la URL del endpoint (HTTPS obligatorio)
- Suscribe los event types (multi-select)
- Copia el signing secret (solo se muestra una vez)
- Pulsa «Send test payload» — el endpoint debe responder con
2xxen 5 segundos, si no el test cuenta como fallido
Event Types
| Event | Trigger |
|---|---|
article.generated |
Job POST /v1/articles/{id}/generate finalizado |
article.optimized |
Job POST /v1/articles/{id}/optimize finalizado |
article.published |
Publish CMS finalizado (o fallido) |
tracking.run.completed |
Tracking run con todas las plataformas LLM completo |
tracking.report.ready |
Job generate-report finalizado |
content_audit.completed |
Crawl content-audits finalizado |
content_optimizer.completed |
Análisis Optimizer finalizado |
competitor_analysis.completed |
Análisis de competencia finalizado |
backlinks.refreshed |
Delta pull o full pull finalizado |
humanize.batch.completed |
Batch del Humanizer finalizado |
bulk_generation.completed |
Bulk article generation finalizado |
pipeline.stage.completed |
Stage de pipeline finalizado (para reacciones stage-by-stage) |
keyword.expansion.completed |
Expansión A→Z finalizada |
Estructura del payload
Todos los eventos comparten el mismo envoltorio:
{
"id": "evt_01HW9X8KRJV4M5PXAM",
"type": "article.generated",
"created_at": "2026-04-30T12:14:22Z",
"team_id": 3,
"data": {
"article_id": 88,
"project_id": 12,
"status": "ready",
"credits_used": 5,
"url": "https://rankion.ai/api/v1/articles/88"
}
}
El objeto data varía según el event type. Para detalle, carga el recurso completo vía data.url por la API REST — los payloads de webhook se mantienen pequeños a propósito, para no chocar con los body limits de los receptores (Slack, Zapier).
Ejemplo tracking.run.completed
{
"id": "evt_01HW9XBQS...",
"type": "tracking.run.completed",
"created_at": "2026-04-30T15:00:11Z",
"team_id": 3,
"data": {
"tracking_project_id": 7,
"run_id": 142,
"platforms": ["chatgpt","perplexity","claude"],
"avi_score": 64,
"delta_vs_previous": "+8",
"url": "https://rankion.ai/api/v1/tracking-projects/7/avi"
}
}
Firma HMAC
Cada request lleva el header X-Rankion-Signature — una firma HMAC-SHA256 del raw body con el signing secret. Verifícala siempre antes de confiar en el payload.
import hmac, hashlib
def verify(body: bytes, signature_header: str, secret: str) -> bool:
expected = hmac.new(secret.encode(), body, hashlib.sha256).hexdigest()
return hmac.compare_digest(expected, signature_header.replace("sha256=", ""))
function rankion_verify_webhook(string $rawBody, string $sigHeader, string $secret): bool {
$expected = hash_hmac('sha256', $rawBody, $secret);
return hash_equals($expected, str_replace('sha256=', '', $sigHeader));
}
Formato del header: X-Rankion-Signature: sha256=<hex>. Adicionalmente: X-Rankion-Event (event type) y X-Rankion-Delivery (delivery ID único — ideal para checks de idempotencia).
Idempotencia
Por reintentos, un mismo evento puede entregarse varias veces. Guarda los X-Rankion-Delivery recibidos durante al menos 24 h e ignora repeticiones.
Lógica de reintentos
Si tu endpoint no responde con 2xx en 5 segundos, Rankion reintenta con backoff exponencial:
| Intento | Delay |
|---|---|
| 1 | inmediato |
| 2 | +30 s |
| 3 | +5 min |
| 4 | +30 min |
| 5 | +2 h |
| 6 | +6 h |
Tras el 6.º intento fallido, la subscripción se desactiva automáticamente y recibes una notificación por e-mail. Reactívala vía UI tras el fix.
Las respuestas 4xx (p. ej. 401, 403, 410) cuentan como fallo permanente → sin reintento, desactivación inmediata. Los 5xx y timeouts disparan el retry loop.
Ejemplo: receptor Express
import express from "express";
import crypto from "crypto";
const app = express();
const SECRET = process.env.RANKION_WEBHOOK_SECRET;
app.post("/webhooks/rankion",
express.raw({ type: "application/json" }),
(req, res) => {
const sig = req.headers["x-rankion-signature"]?.replace("sha256=","");
const expected = crypto.createHmac("sha256", SECRET)
.update(req.body).digest("hex");
if (!sig || !crypto.timingSafeEqual(Buffer.from(sig), Buffer.from(expected))) {
return res.status(401).send("invalid signature");
}
const event = JSON.parse(req.body.toString());
console.log(`Got ${event.type}:`, event.data);
// ack first, process async
res.status(200).send("ok");
handleEvent(event).catch(console.error);
}
);
Notas y pitfalls
- Responde rápido, procesa async. Procesamiento pesado en el receptor bloquea el timer de 5 s. Devuelve
200primero, encola después. - Solo HTTPS. Las URLs HTTP se rechazan directamente en la UI.
- Pruebas locales: ngrok / cloudflared tunnel sobre el puerto local → introduce la URL en la UI de webhooks.
- Sin garantía de orden. Si disparas
article.generatedyarticle.optimizedpara el mismo artículo en sucesión rápida, pueden llegar desordenados. Ordena en el receptor porcreated_at. - La sección de webhooks aún es joven. Si te falta un event type → con Automation-Pipelines puedes lograr el mismo efecto interno, o pide la feature a soporte.
Relacionado: Visión general de la API · Automation · Créditos.