Webhooks
Webhook events notify you when demo/highlight processing reaches a terminal state.
Configure webhook destination
Set your callback URL in Rankacy dashboard for the same token/account that uploads demos and queues highlights.
Event delivery requires a configured webhook URL.
Event types
Processing events emitted by the API:
demo.processed.successdemo.processed.failedhighlight.processed.successhighlight.processed.failed
When each event is emitted
demo.processed.*: when a demo transitions to terminal status (SUCCESS/FAILED)highlight.processed.*: when a highlight transitions to terminal status (SUCCESS/FAILED)
Failed events include data.error.message; data.error.code is optional.
Events
demo.processed.success
{
"id": "evt_2e4f7a4f-4afb-45a4-9538-0ed84f703db8",
"type": "demo.processed.success",
"created_at": "2026-02-12T12:21:39.146102Z",
"data": {
"demo_id": 52,
"status": "success"
}
}
demo.processed.failed
{
"id": "evt_4d2f6f89-6f7f-4c5b-9af3-4d9e260fd2da",
"type": "demo.processed.failed",
"created_at": "2026-02-12T12:23:01.481032Z",
"data": {
"demo_id": 52,
"status": "failed",
"error": {
"message": "Parser crashed",
"code": "PARSER_ERROR"
}
}
}
error.code is optional.
highlight.processed.success
{
"id": "evt_4f7f546b-d8ef-4761-91dd-d0da6fa6ce7e",
"type": "highlight.processed.success",
"created_at": "2026-02-18T11:06:34.145091Z",
"data": {
"highlight_id": 311,
"demo_id": 52,
"status": "success"
}
}
highlight.processed.failed
{
"id": "evt_59f7ff0b-74f2-4b8e-b62e-1f46dcb6a5af",
"type": "highlight.processed.failed",
"created_at": "2026-02-18T11:07:01.962932Z",
"data": {
"highlight_id": 311,
"demo_id": 52,
"status": "failed",
"error": {
"message": "Highlight processing failed",
"code": "RUNTIME_ERROR"
}
}
}
error.code is optional.
Payload notes
id: stable event identifier (reused across retries for the same event)type: one of the four event types abovecreated_at: UTC timestamp in ISO 8601 formatdata.demo_id: always present for demo and highlight eventsdata.highlight_id: present only forhighlight.processed.*data.status:successorfaileddata.error: present only on*.failedevents
Delivery behavior
- asynchronous dispatch from worker loop
- at-least-once delivery
- retries for non-2xx responses/network errors
- event enqueue is idempotent per user + resource + event type
Default retry configuration:
- max attempts:
6 - schedule (seconds):
30, 120, 300, 900, 1800, 3600 - additional jitter: up to
10s - timeout per attempt:
5s
A 2xx response marks delivery as success.
Request headers
Each webhook POST includes:
Content-Type: application/jsonX-Event-Id: <event_id>X-Event-Type: <event_type>X-Request-Id: <event_id>
Idempotency
Because delivery is at-least-once, deduplicate by event ID.
Recommended key:
X-Event-Idheader, or- JSON body field
id
FastAPI receiver example
from fastapi import FastAPI, Request, HTTPException
app = FastAPI()
seen_event_ids = set() # Replace with Redis/DB in production
@app.post("/rankacy/webhook")
async def rankacy_webhook(request: Request):
event_id = request.headers.get("X-Event-Id")
event_type = request.headers.get("X-Event-Type")
payload = await request.json()
if not event_id:
event_id = payload.get("id")
if not event_id:
raise HTTPException(status_code=400, detail="Missing event id")
if event_id in seen_event_ids:
return {"ok": True, "duplicate": True}
seen_event_ids.add(event_id)
# Business logic
print({"event_id": event_id, "event_type": event_type, "payload": payload})
return {"ok": True}
Production note:
- use durable idempotency storage (Redis/DB), not in-memory set
Signature verification
No cryptographic webhook signature header is currently emitted by this API.
Current hardening recommendations:
- require HTTPS
- restrict source IP/network where possible
- use idempotency checks
- monitor delivery outcomes in your integration logs
Local testing (ngrok)
Run your webhook server locally (for example on localhost:9000) and tunnel it:
ngrok http 9000
Set the generated HTTPS URL in Rankacy webhook settings.
End-to-end FastAPI showcase
For a working integration example (demo upload + highlight queue + webhook receiver), see:
- FastAPI Showcase
docs/examples/fastapi_public_demo_webhook_showcase.py