ReferenceEvents and execution

Webhooks

Headers, signature construction, payload schema, and retry policy for run events.

Add an HTTPS webhook URL to a routine and every finished run produces a signed event. Work on Repeat returns the signing secret once and stores only its encrypted form.

For the receiver walkthrough, see Receive run webhooks.

Headers

Content-Type: application/json
X-Work-On-Repeat-Event: run.succeeded | run.failed
X-Work-On-Repeat-Request-Id: <stable across retries>
X-Work-On-Repeat-Timestamp: <unix seconds>
X-Work-On-Repeat-Signature: v1=<hex hmac-sha256>

Signature

signed_payload = timestamp + "." + raw_request_body
signature       = "v1=" + hex(hmac_sha256(webhook_secret, signed_payload))

Verify against the exact bytes received, compare in constant time, and reject timestamps outside a five-minute window before doing any work.

Payload

Every event shares a base:

Prop

Type

run.succeeded

{
  "version": 1,
  "event": "run.succeeded",
  "deliveryId": "0f2e9d1c-…",
  "occurredAt": "2026-08-10T09:03:41.522Z",
  "projectId": "5a41c0de-…",
  "routine": { "id": "9c2e…", "name": "Weekly security audit" },
  "run": {
    "id": "1f7b0e6a-…",
    "state": "succeeded",
    "trigger": "schedule",
    "output": "Five findings, ranked…",
    "error": null
  }
}

output is always a non-empty string on success; a run that produced no text is delivered as "Routine completed without text output.".

run.failed

{
  "version": 1,
  "event": "run.failed",
  "deliveryId": "3b81a44f-…",
  "occurredAt": "2026-08-10T09:21:07.004Z",
  "projectId": "5a41c0de-…",
  "routine": { "id": "9c2e…", "name": "Weekly security audit" },
  "run": {
    "id": "77c1de90-…",
    "state": "failed",
    "trigger": "schedule",
    "output": null,
    "error": {
      "category": "gateway_timeout",
      "message": "The gateway did not respond in time.",
      "retryable": true
    }
  }
}

retryable is true for gateway_error, gateway_rate_limit, gateway_timeout, mcp_transport, and timeout. It describes whether repeating the work is reasonable — Work on Repeat does not re-execute the run itself.

Only completed and failed runs are delivered

There are no events for queued, claimed, or running. A run that ends cancelled or timed_out is recorded on the run, and timed_out is delivered as run.failed with the timeout category.

Delivery behaviour

Deliveries are persisted before they are sent, then claimed and attempted by the one-minute operations tick.

ResponseOutcome
2xxDelivered.
429, 5xxRetried with backoff.
Network error or timeoutRetried with backoff.
Other 4xxExhausted immediately; not retried.
RedirectNot followed.

Four attempts maximum. Backoff starts at 30 seconds and doubles, capped at 30 minutes, with jitter. Request timeout is 10 seconds.

Each attempt is recorded on the run with its attempt number and response code, visible in the run detail.

Rotating the secret

Set the routine's webhook URL again. The response returns a fresh webhookSecret once, and the previous secret stops verifying. Clearing the URL removes the stored secret entirely.

On this page

Edit this page on GitHub