Skip to main content

Webhook

Receive external POST deliveries at a saved ActionFlow webhook URL, with token, idempotency, validation, passive-flow, and response-status behavior.

Webhook

An inbound flow webhook is a setting on a saved ActionFlow. It is not a fourth start-node type: use a graph with a Start node, create the webhook from the flow's Webhooks settings, and send requests to the generated URL.

There is at most one active inbound flow webhook per flow. Organization outgoing event webhooks are a different feature; see Webhooks overview.

URL shape

The URL is built from NEXT_PUBLIC_WEB_URL:

${NEXT_PUBLIC_WEB_URL}/app/webhooks/actionflows/{actionFlowId}/{token}

For the production web host, the shape is:

https://actionflows.ai/app/webhooks/actionflows/{actionFlowId}/{token}

The Endpoint card in the flow settings is the source of truth. The path contains the ActionFlow ID and the secret webhook token; it is not app.actionflows.ai/webhooks/....

POST-only request

The flow webhook route exports POST only. Other HTTP methods are not accepted by this endpoint and are rejected by the route framework. The token in the path is the request credential; a REST API key is not required for this URL.

Send a JSON object when you want its fields to become run inputs:

curl -X POST https://actionflows.ai/app/webhooks/actionflows/{actionFlowId}/{token} \
  -H "Content-Type: application/json" \
  -H "X-Idempotency-Key: order-created-ORD-12345" \
  -d '{
    "node_start_orderId": "ORD-12345",
    "event": "order.created",
    "data": {
      "total": 299.99
    }
  }'

Use {nodeId}_{inputName} when a field must override a node input. The complete request is also merged into the trigger envelope as body, headers, query, and method. Only a small allowlist of request headers is copied into the envelope, including content-type, user-agent, x-request-id, and x-idempotency-key.

The webhook run has triggerSource: "webhook". The platform adds source:webhook, flow:{actionFlowId}, and organization:{organizationId} tags; callers cannot replace those tags through the webhook body.

Idempotency

X-Idempotency-Key is read case-insensitively from the request and passed to the execution service with the webhook run. Use a stable key for a logical delivery and reuse it when retrying the same event. The key is separate from the path token and does not authenticate a different webhook.

X-Idempotency-Key is applied to the local admission record, scoped by organization and actionFlowId; the lookup does not compare request payloads. Reusing a key for a different payload in the same organization and ActionFlow refers to the existing admission. In direct admission mode, success requires the execution response to contain a runtime id; an otherwise successful response without that id is an admission failure and may leave a history row in executing. A direct duplicate whose existing admission is executing/not dispatched and lacks triggerRunId also fails. A dispatched direct duplicate with a triggerRunId is successful; this webhook returns HTTP 202 with runtime status: dispatched for that existing admission. In queue mode, a waiting duplicate can be republished, and a dispatched duplicate with a triggerRunId also returns HTTP 202 with runtime status: dispatched. A dispatched duplicate without a triggerRunId and failed or cancelled terminal duplicates are unavailable and return a generic 500; none is admitted as a new run. Retain the returned runId or queueId and the original key when investigating duplicates.

Response statuses

StatusMeaning
202The request was accepted and the run was dispatched or placed in the queue.
403The webhook record exists but is disabled.
404The token or ActionFlow path does not identify a live webhook, or the flow was deleted.
409The flow is passive (active: false); the request is rejected before enqueue.
422validateFlow rejected the saved graph before the webhook input envelope was merged. No run is enqueued.
429The organization and client-IP rate limit was exceeded.
401The handler's timing-safe token guard can reject a mismatched token; clients should treat it like invalid credentials.
405A non-POST method was sent to this POST-only route.
500The webhook was found but the run could not be admitted or an unexpected handler error occurred.

The handler checks the webhook record, enabled flag, active state, and rate limit before it validates or enqueues the run. A passive flow therefore returns 409 rather than a run ID. Enable the webhook and activate the flow when external delivery should be accepted.

202 response shapes

An immediately dispatched run can return:

{
  "success": true,
  "runId": "run_123",
  "status": "dispatched"
}

A queued run can return:

{
  "success": true,
  "queueId": "queue_123",
  "status": "waiting"
}

runId and queueId are optional fields, but the successful response contains at least one of them. A 202 means accepted, not completed. The List Queued Runs endpoint is only an active waiting/dispatching view and may stop showing the item after dispatch. Use queueId with Get Queued Run to observe dispatched, failed, or cancelled and retrieve triggerRunId when present; then follow the runtime ID through Run history or Get Run.

Validation timing

The webhook parses and records the delivery, then calls validateFlow on the saved graph before calling the enqueue function. The JSON body and request-envelope fields are not merged into the graph for this pre-enqueue validation. If the saved graph has a missing required input, fix and save the graph rather than expecting a webhook body value to bypass the 422 check. The 422 body uses errors and warnings (the REST endpoint uses validationErrors and validationWarnings for its 400 response).

A request that returns 202 may still fail later during execution. Inspect run history and the queue when the graph, credentials, credits, or a node is the source of the failure.

Security and operations

  • Treat the path token as a secret. Regenerate it from the webhook settings if it may have leaked; the old URL then stops resolving to the webhook.
  • Deleted webhooks and deleted flows stop accepting deliveries.
  • Disabled webhooks return 403; passive flows return 409.
  • The handler rate-limits by organization and client IP. Do not retry a 429 in a tight loop.
  • Do not put credentials or sensitive payloads into logs, tickets, or public examples.

Webhook versus API

Flow webhookREST POST /api/runs
CallerAn external system using the generated URLA backend or authenticated application request; external integrations should use an API key
CredentialSecret token in the pathAPI key for external integrations; the REST route also accepts an authenticated application session
Saved graphStart-compatible graph with a configured webhookStart-compatible graph selected by IDs
Sourcewebhookapi for an API key or manual for an authenticated session by default
Validation failure422 before enqueue400 before enqueue

On this page