Skip to content

Webhooks

Workflows can receive events from external systems via a webhook endpoint. This enables integration with approval systems, payment processors, CI/CD pipelines, and any other service that can send HTTP requests.

The Webhook Endpoint

External events are sent to:

POST /workflows/api/webhook/{conversation_id}/{state_name}

The state_name parameter specifies the workflow state the conversation is expected to be in. If the conversation’s active workflow run is in a different state, the request is rejected with a 409 Conflict response.

The request body is JSON:

{
  "event_key": "approval_granted",
  "data": {
    "approver": "jane@example.com",
    "comment": "Looks good, approved."
  }
}
FieldRequiredDescription
event_keyYesA string identifier that matches an external_event guard on a transition
dataNoOptional key-value data to merge into the workflow’s gathered data

The endpoint returns 200 OK on success (with the new state if a transition fired), 401 Unauthorized if the token is invalid, 404 Not Found if the conversation does not exist, and 409 Conflict if the conversation is not in the expected state.

Authentication

Webhook requests are authenticated using a reply token. Each workflow conversation generates a unique reply token when it enters a state with an external_event guard. The token can be provided in two ways:

  • Authorization headerAuthorization: Bearer <token>
  • Query parameter?token=<token>

The token is:

  • Included in any outbound notifications sent by the workflow (e.g., approval request emails)
  • Available in gathered data as reply_token for use in HTTP tool calls
  • Scoped to the specific conversation – it cannot be reused for other workflows

There is no separate API key or shared secret. The reply token serves as both identifier and credential.

Triggering Transitions

When the webhook receives a valid event:

  1. The event_key is stored in the workflow run’s gathered data
  2. Any additional data in the request body is merged into gathered data
  3. The engine evaluates external_event guards on the current state’s outgoing transitions
  4. If a matching guard is found and all other guards on that transition also pass, the workflow advances
  5. The response includes the new state name if a transition fired, or a no_transition indicator if no guard matched

Example: Approval System

A typical approval integration works like this:

  1. The workflow reaches a Request Approval state
  2. The assistant sends an approval request email to the manager, including a link with the reply_token
  3. The manager clicks “Approve” or “Deny” in the external approval system
  4. The approval system calls the webhook:
POST /workflows/api/webhook/{conversation_id}/request_approval?token=abc123...
{
  "event_key": "approval_granted",
  "data": {
    "approver": "manager@example.com",
    "approved_at": "2026-03-31T10:00:00Z"
  }
}
  1. The external_event guard on the “Request Approval -> Update Calendar” transition fires
  2. The workflow advances and the assistant proceeds with the next step

For the denial path, a separate transition with external_event guard matching approval_denied routes to a terminal state.

For simple approval flows that don’t require an external system, consider using the built-in approval gate feature instead. Set require_human_approval: true on a state and the workflow engine handles the approval UI, email notifications, and resume/reject flow automatically.
You can test webhook integration during development by using the Send Event button on the workflow progress panel in the conversation view. This simulates an external event without needing a real external system.
Technical Details

Reply token generation – Reply tokens are generated as URL-safe random strings when the workflow engine detects that the current state has an outgoing transition with an external_event guard. The token is stored on the conversation record and rotated each time the workflow enters a new state that expects external events.

Event storage – Incoming events are stored in the workflow_events table with the conversation ID, event type, data payload, and timestamp. This provides an audit trail and allows events that arrive early (before the workflow reaches the waiting state) to be replayed when the state is entered.

Idempotency – Duplicate events (same reply token and event type) are deduplicated. The first event triggers the transition; subsequent duplicates are acknowledged with 200 but do not re-trigger.