Webhooks (API reference)
This page covers webhook configuration when dispatching a run. For event payload shapes, see Events. For signature verification, see Signatures. For retry behavior, see Retries.
Webhook configuration object
Include a webhook object in your POST /v1/runs request body to receive events for that run:
{
"url": "https://your-app.com/hooks/rundun",
"secret": "whsec_abc123",
"events": ["step.completed", "run.completed", "run.cancelled", "run.expired"]
}
Fields
| Field | Type | Required | Description |
|---|---|---|---|
url |
string | yes | HTTPS endpoint that receives POST requests. Must return 2xx within 10 seconds. |
secret |
string | yes | Used to sign deliveries. Minimum 16 characters. You choose this value and use it to verify incoming requests. |
events |
array | yes | Event names to subscribe to. Use ["*"] to subscribe to all events. |
Example: subscribe to all events
"webhook": {
"url": "https://your-app.com/hooks/rundun",
"secret": "whsec_abc123",
"events": ["*"]
}
Example: only the final result
Omitting step.completed is common when you only need the final outcome. This significantly reduces webhook volume for long checklists.
"webhook": {
"url": "https://your-app.com/hooks/rundun",
"secret": "whsec_abc123",
"events": ["run.completed", "run.cancelled", "run.expired"]
}
Available events
| Event | Fires when | Typical use |
|---|---|---|
step.completed |
A step is answered (all required photos taken) | Live progress tracking, streaming updates |
step.skipped |
A non-required step is explicitly skipped | Audit trail |
run.completed |
All required steps answered, run submitted | Trigger downstream workflows, save results |
run.cancelled |
Executor exits before completion | Alert, reassign, reopen |
run.expired |
Run link expires | Reopen, investigate, alert |
Delivery
Every delivery is a POST request to your URL with:
Content-Type: application/json- Three signature headers (
Content-Digest,Signature-Input,Signature) - A JSON body with the event envelope
Your endpoint must return any 2xx status within 10 seconds. Any other response — including 3xx redirects, 4xx, 5xx, or a timeout — is treated as a failure and triggers the retry schedule.
Event subscription scope
Webhook subscriptions are per-run, set at dispatch time. There is no global or per-template webhook configuration. This means:
- Different runs can send events to different endpoints
- You can run the same template with different webhook configs for different integrations
- Changing webhook settings requires dispatching a new run — you cannot modify a run's webhook config after dispatch
Payload envelope
All events share the same outer envelope:
{
"event_id": "evt-550e8400-e29b-41d4-a716-446655440000",
"delivery_attempt": 1,
"event": "step.completed",
"run_id": "r-550e8400-e29b-41d4-a716-446655440000",
"template_id": "t-a3f9bc00-e29b-41d4-a716-446655440000",
"template_v": 3,
"ts": "2026-05-22T08:33:12Z",
"identity": {
"mode": "member",
"user_id": "u-abc12300-e29b-41d4-a716-446655440000"
},
"data": { }
}
| Field | Description |
|---|---|
event_id |
Stable UUID per event — identical on every retry attempt. Use as idempotency key. |
delivery_attempt |
Which attempt this is (1–5). Increments on each retry. |
event |
The event type string |
run_id |
The run this event belongs to (r-{uuid}) |
template_id |
The template this run is based on (t-{uuid}) |
template_v |
Template version snapshotted at run creation |
ts |
ISO 8601 timestamp of the event |
identity |
How the executor identified themselves (see Concepts) |
data |
Event-specific payload — see Events for each shape |
Testing webhooks
You can replay webhook deliveries from the creator dashboard at my.rundun.app under Runs → [run] → Webhook deliveries. Use a tool like webhook.site or ngrok during development to inspect payloads.