Skip to main content
This guide walks through the full receive path: create a subscription, accept a delivery, verify the signature, dedupe retries, and round-trip a synthetic webhook.test event before going live. For the mental model — fleet scope, delivery semantics, ordering — see Webhooks.

Subscribe

Create the subscription against the fleet that owns the agents you want to hear about. Pass the HTTPS endpoint that will receive deliveries and, optionally, the events to filter to. Omit events to subscribe to every non-test event.
The response contains the subscription metadata plus the signing secret:
The secret field is returned only on create and rotate. Store it somewhere you can read from your receiver — a secrets manager, Workers secret, or environment variable. Cerca will not show it again.

Receive

Every delivery is a POST with a JSON body and four headers you care about: A minimal Cloudflare Worker handler looks like this:
Return a 2xx status to acknowledge the delivery. The runtime retries once on network errors, 429 responses, and 5xx responses; other non-2xx responses (400, 401, 403, 404, etc.) are recorded as a failure with no retry, so use 5xx if you want the runtime to try again.

Verify

The signing string is ${timestamp}.${payload} — the value of X-Agent-Timestamp, a single dot, and the raw request body. Strip the sha256= prefix from the header value before comparing, reject deliveries whose timestamp drifts too far (5 minutes is a reasonable default), and compare in constant time so a bad signature does not leak timing.
Verify against the raw body bytes that arrived. Reading the body once and reusing the same string for both the signature check and JSON.parse is the safest pattern — re-serializing parsed JSON will not match the signature.

Handle retries idempotently

Deliveries are at-least-once, so your handler must tolerate seeing the same event twice. The X-Agent-Delivery-Id header is stable across retries of a given delivery — claim it atomically and skip work you have already done:
Ordering is not guaranteed either. When ordering matters, reconcile against your own state — for example, ignore a thread.status.changed event if you have already recorded a later state for that thread.

Test

The test endpoint fires a synthetic webhook.test event end-to-end against your URL using the real signing secret. It is the fastest way to confirm the full receive-and-verify path works before any real event fires.
The response reports the structured delivery result:
A success: false result means the runtime could not reach your handler or got a non-2xx response. The delivered event has event: "webhook.test" and an empty data object, so ignore unknown event types in your handler rather than treating them as errors. webhook.test is reserved for the test endpoint and cannot be added to a subscription’s events array on create or update.

Rotate

Rotate the secret if you suspect it leaked, on a regular schedule, or before retiring an old receiver. Rotation issues a new secret and invalidates the old one immediately.
The response shape matches create — the new secret is returned as secret and is not retrievable later. To rotate without dropped deliveries, configure your receiver to accept either the old secret or the new one for an overlap window, deploy that change, run the rotate call, and remove the old secret once you have confirmed nothing is still signing with it.