- Per-request — include
webhook_urlon a single generation call. One-shot; fires once for that task. - Subscriptions — call
POST /webhooksonce per org; fires for every matching event thereafter.
Events
Currently we fire two events:run.completed— a task transitioned tostatus=completedrun.failed— a task transitioned tostatus=failed
events field when subscribing
(see below). Subscribe only to the events you actually handle.
Subscribing
secret is shown only once. Save it — you need it to verify
signatures. Losing it means deleting the subscription and creating a new
one.
Per-request webhooks
If you just want a single callback for one task:GET /verify), not a per-subscription one. Same signature scheme.
Payload shape
run.failed the shape is:
Verifying signatures
The signature is computed as:timestamp is the X-Overten-Timestamp header value and
raw_body is the exact bytes of the POST body (not re-serialized JSON).
Retry policy
Non-2xx responses trigger retries with exponential backoff:Best practices
Respond fast, process async
Respond fast, process async
Return
200 immediately and enqueue the work internally. We time out
at 15 seconds per attempt; if your handler runs synchronously longer
than that we’ll treat it as a failure.Be idempotent on run_id + event
Be idempotent on run_id + event
Retries and edge cases can cause duplicate deliveries. Key your
processing on
(run_id, event) and skip if already handled.Verify signatures
Verify signatures
Webhook URLs are attacker-reachable. Signatures prove it came from us.
Never trust the payload without verifying.
Store the secret like a database password
Store the secret like a database password
If it leaks, rotate by deleting the subscription and recreating it —
the new subscription will issue a fresh secret. Old signatures will
stop validating immediately.
Debugging
The dashboard’s Webhooks → Delivery log shows every attempt for the last 30 days with:- HTTP status received
- Response body (truncated to 1KB)
- Latency per attempt
- Retry schedule remaining
