All routes require Authorization: Bearer <project-api-key>. Because endpoints receive project-wide execution events, user-pinned keys receive 403 auth_insufficient_scope.

Create an endpoint

POST /v1/webhooks

JSON
{
  "url": "https://example.com/webhooks/eyeball",
  "events": ["execution.completed", "voice.session.event"],
  "active": true
}

The 201 response includes endpointId, normalized url, events, active, createdAt, updatedAt, secretPrefix, and the complete secret. The complete secret appears only in this response.

Supported subscriptions are execution.completed, execution.succeeded, execution.failed, execution.cancelled, voice.session.event, voice.transcript.ready, voice.observer.failed, trigger.*, and exact canonical trigger event types such as trigger.slack.message_received. The execution.completed selector matches all three terminal execution events.

voice.observer.failed is an executor-owned terminal observation signal, not a worker-sequenced lifecycle event. Its data contains sessionId, pinned agentId/agentRevision, lastHandledSequence, attempts, reason (retry_exhausted or non_retryable), a safe observer operation, and a normalized public error. It does not alter the worker-owned session state; use the stable webhook event ID for receiver deduplication.

List and get endpoints

  • GET /v1/webhooks?limit=100&cursor=... returns { webhooks, nextCursor? }.
  • GET /v1/webhooks/:endpointId returns one endpoint or 404.

List and get responses never include secret.

Update an endpoint

PATCH /v1/webhooks/:endpointId accepts any non-empty combination of url, events, and active. The response contains the updated endpoint without its signing secret. Every attempt resolves the endpoint's current URL, secret, and active state, so a URL change affects the next attempt and deactivation prevents unfinished delivery work from continuing rather than pausing it.

Rotate a signing secret

POST /v1/webhooks/:endpointId/rotate-secret replaces the signing secret immediately. The response includes the new secret and secretPrefix; the complete secret appears only in this rotation response. Every attempt, including a retry that is already queued, resolves the current secret and uses the replacement. The previous secret is invalid as soon as rotation succeeds.

Delete an endpoint

DELETE /v1/webhooks/:endpointId returns 204 or 404. Deletion prevents new scheduling and unfinished delivery work from continuing. It does not rewrite stored historical rows, but endpoint-scoped delivery history is no longer accessible through the public route after deletion.

Inspect deliveries

GET /v1/webhooks/:endpointId/deliveries?limit=100&cursor=... returns { deliveries, nextCursor? }. Each delivery includes:

  • deliveryId, eventId, eventType, and endpointId;
  • status: pending, delivering, succeeded, or failed;
  • append-only attempts with timestamps, response status code, or a sanitized transport error;
  • nextRetryAt while another attempt is scheduled and completedAt after success or give-up.

Delivery responses are metadata-only. They never include the delivered payload, signing secret, request or receiver response body, or receiver headers.

The project Webhooks screen in the dashboard exposes endpoint CRUD, event selection, reveal-once create and rotation secrets, confirmed destructive actions, and this metadata-only delivery history. It uses the selected project's executor path in both demo and cloud mode.

Read Webhooks for signature verification, event envelopes, retries, ordering, and production durability requirements.