Webhooks
Job-Completions per HTTP an deinen Endpoint pushen — statt zu pollen.
Webhooks sind der Push-Pfad der Rankion-API: statt nach jedem 202 Accepted einen Polling-Loop aufzubauen, registrierst du einen HTTPS-Endpoint und Rankion liefert Job-Completions per POST aus, sobald sie fertig sind. Ideal für Integrationen mit Zapier/Make, eigenen Backends oder Slack-Notifications. Webhooks sind komplementär zu Automation (interne Pipelines) — sie verlassen die Plattform.
Status: Outbound-Webhooks befinden sich in Planung. Aktuell existiert nur ein Inbound-Webhook für externe Review-Quellen:
POST /api/v1/webhooks/reviews/{source}(key-basiert, kein Sanctum, siehe Review Sources). Eine generelle UI unter/settings/webhooksmit Subscription-Verwaltung und HMAC-Signierung ist noch nicht ausgerollt. Die unten beschriebene Event-Liste, Payload-Hülle und HMAC-Verifikation sind die geplante Konvention — sie kann sich vor Release noch ändern. Für sofortige Job-Status-Updates: REST-Polling auf den jeweiligen Detail-Endpoint nutzen.
Konfiguration (UI) — geplant
Webhook-Endpoints werden (nach Release) im Frontend unter /settings/webhooks angelegt:
- Endpoint-URL eintragen (HTTPS Pflicht)
- Event-Types abonnieren (Multi-Select)
- Signing-Secret kopieren (wird nur einmal angezeigt)
- "Send test payload" klicken — der Endpoint muss innerhalb 5 Sekunden mit
2xxantworten, sonst gilt der Test als fehlgeschlagen
Event-Types
| Event | Trigger |
|---|---|
article.generated |
POST /v1/articles/{id}/generate Job fertig |
article.optimized |
POST /v1/articles/{id}/optimize Job fertig |
article.published |
CMS-Publish abgeschlossen (oder gefailed) |
tracking.run.completed |
Tracking-Run mit allen LLM-Plattformen durch |
tracking.report.ready |
generate-report-Job fertig |
content_audit.completed |
content-audits Crawl abgeschlossen |
content_optimizer.completed |
Optimizer-Analyse fertig |
competitor_analysis.completed |
Konkurrenz-Analyse fertig |
backlinks.refreshed |
Delta-Pull oder Full-Pull abgeschlossen |
humanize.batch.completed |
Humanizer-Batch fertig |
bulk_generation.completed |
Bulk-Article-Generation fertig |
pipeline.stage.completed |
Pipeline-Stage abgeschlossen (für Stage-by-Stage-Reactions) |
keyword.expansion.completed |
A→Z-Expansion fertig |
Payload-Struktur
Alle Events haben dieselbe Hülle:
{
"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"
}
}
Das data-Objekt variiert je Event-Type. Für Details lade den vollen Resource via data.url über die REST-API — Webhook-Payloads halten sich bewusst klein, um Body-Limits in Empfängern (Slack, Zapier) zu schonen.
Beispiel 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"
}
}
HMAC-Signatur
Jede Request enthält einen X-Rankion-Signature Header — eine HMAC-SHA256-Signatur des Raw-Bodies mit dem Signing-Secret. Verifiziere sie immer, bevor du der Payload trust.
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));
}
Header-Format: X-Rankion-Signature: sha256=<hex>. Zusätzlich: X-Rankion-Event (Event-Type) und X-Rankion-Delivery (Unique Delivery-ID — ideal für Idempotenz-Checks).
Idempotenz
Aufgrund von Retries kann derselbe Event mehrfach geliefert werden. Speichere eingehende X-Rankion-Delivery-IDs für mindestens 24 h und ignoriere Wiederholungen.
Retry-Logik
Liefert dein Endpoint nicht innerhalb 5 Sekunden mit 2xx, retried Rankion mit exponentiellem Backoff:
| Versuch | Delay |
|---|---|
| 1 | sofort |
| 2 | +30 s |
| 3 | +5 min |
| 4 | +30 min |
| 5 | +2 h |
| 6 | +6 h |
Nach dem 6. fehlgeschlagenen Versuch wird die Subscription automatisch deaktiviert und du bekommst eine E-Mail-Notification. Reaktivieren via UI nach Behebung.
4xx-Antworten (z.B. 401, 403, 410) gelten als permanente Failure → kein Retry, sofortige Deaktivierung. 5xx und Timeouts triggern den Retry-Loop.
Beispiel: Express-Empfänger
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);
}
);
Hinweise & Pitfalls
- Antworte schnell, verarbeite async. Schwere Verarbeitung im Empfänger blockt den 5-s-Timer. Erst
200zurückgeben, dann queue'n. - Nur HTTPS. HTTP-URLs werden im UI direkt abgelehnt.
- Lokales Testen: ngrok / cloudflared tunnel auf lokalen Port → URL ins Webhook-UI eintragen.
- Keine Garantie auf Reihenfolge. Wenn du
article.generatedundarticle.optimizedfür denselben Artikel kurz hintereinander triggerst, können sie unsortiert ankommen. Sortiere im Empfänger nachcreated_at. - Webhook-Sektion noch jung. Falls ein Event-Type fehlt, den du brauchst → über Automation-Pipelines lässt sich derselbe Effekt intern erzielen, oder Feature-Request über Support.
Verwandt: API-Übersicht · Automation · Credits.