Skip to content

HTTP Sink

The HTTP sink allows you to trigger workflow executions via standard HTTP requests. This is the most flexible sink type, supporting any HTTP method and custom paths.

POST/GET/PATCH/DELETE /api/v1/sink/trigger/http/{app_id}{path}
  • app_id: Your application’s unique identifier
  • path: Custom path you configure (must start with /)

A service on a device you manage answers at its own address instead; see On a device.

FieldTypeDescriptionRequired
pathstringURL path for the endpoint (e.g., /webhook)Yes
methodstringHTTP method (POST, GET, etc.)Yes
auth_tokenstringOptional Bearer token for authenticationNo

When running locally, the desktop app exposes an HTTP server on port 9657:

http://localhost:9657/{app_id}{path}
Terminal window
curl -X POST "http://localhost:9657/app_abc123/webhook" \
-H "Content-Type: application/json" \
-d '{"event": "test", "data": {"key": "value"}}'

When deployed to a server, the endpoint is publicly accessible:

https://your-domain.com/api/v1/sink/trigger/http/{app_id}{path}
Terminal window
curl -X POST "https://your-domain.com/api/v1/sink/trigger/http/app_abc123/webhook" \
-H "Content-Type: application/json" \
-H "Authorization: Bearer your-auth-token" \
-d '{"event": "test", "data": {"key": "value"}}'

Use Device deployment to install and operate the standalone runtime. Service access and port forwarding explains listener addresses, browser access, and private connections to deployed services.

An http event, or an Endpoint (api event), that is deployed to a device is served by the service it is deployed to, at that service’s own address:

http(s)://<service address>:<port>{path}

The address has no app_id. The device answers with the event and Flow version the service was deployed with, until the service is updated. The hub, or the desktop app, keeps answering at its own address with the live event.

  • Who can reach it is the service’s exposure: only this device, one address, or all networks.
  • Who may call it follows the service’s access settings. By default, callers send Authorization: Bearer <token>. The token is shown once after deployment and can be replaced on the service’s Endpoint tab. Choose No token under Endpoint & limits to allow anyone who can reach the listener to call it. This choice applies to every endpoint, Page, chat, and action in that service. Use separate services when they need different access settings.
  • The event’s auth_token is not used on a device. public_endpoint is not read: the service’s access settings apply regardless of whether the endpoint is open on the hub.
  • Without a certificate on the service, requests and any service token travel unencrypted.
  • Senders that cannot set an Authorization header can call a service configured with No token. The service sends no CORS headers, so removing the token requirement does not enable web pages on other origins to call it.
Terminal window
curl -X POST "https://device.example:8443/webhook" \
-H "Authorization: Bearer <service access token>" \
-H "Content-Type: application/json" \
-d '{"event": "test"}'

Omit the Authorization header when the service uses No token.

A device reads the route as the hub does: path, or path_suffix when there is no path, with a leading / added when it is missing; and method, which is POST when none is saved. The path is literal: at most 2,048 printable ASCII characters without spaces, none of ? # \ { } *, and no . or .. segment. The paths /services, /ui, /ui/… and /channels/… belong to the service itself.

Within one service a method and path can be used once. Two endpoints with the same method and path are refused, and so is an endpoint that uses the route of a chat (POST /chat/{event id}), of a page (GET /pages/{event id}/bootstrap, POST /pages/{event id}/invoke) or of a form or quick action (POST /run/{event id}) of the same service. A device refuses such a service when the deploy is checked, before it replaces a running version. Two services on one device have ports of their own and can use the same route.

TopicOn a device
Query fieldsBecome fields of the payload; a repeated key becomes a list, and key[] always makes one
JSON bodyRead with Content-Type: application/json; the fields of an object join the query fields
Form-encoded bodyRead with Content-Type: application/x-www-form-urlencoded, like query fields
Other bodiesPassed as one text value; together with query fields the request is refused
Multipart bodies (file uploads)Refused with 415
Body size10 MiB at most
AnswerThe payload of the Flow’s last “Return Generic Result”, or {"completed": true}
Flow failed502; the hub answers 200 with its acknowledgement
Time limitThe service’s request time limit. The run is cancelled when it passes and the caller gets 502. A caller that hangs up cancels the run too
Busy429 with Retry-After: 1 while the service runs as many requests as it allows at once
IdentityRuns act as the person who approved the service’s cloud access, or as the device’s local user for an offline app. They carry no personal access token and no signed-in provider tokens
StatusMeaning on a device
200 OKThe Flow finished; the body is its result
400 Bad RequestThe query or the body cannot be read
401 UnauthorizedThe service requires an access token, and the request’s token is missing or wrong
404 Not FoundThe service has no endpoint with this method and path
408 Request TimeoutThe body did not arrive within the time limit
413 Payload Too LargeThe body is larger than 10 MiB
415 Unsupported Media TypeThe body is multipart
429 Too Many RequestsThe service runs as many requests as it allows at once
502 Bad GatewayThe Flow failed or ran past the time limit
503 Service UnavailableThe service is stopping, or a required access token cannot be read

If you configure an auth_token, all requests must include it in the Authorization header:

Terminal window
curl -X POST "https://your-domain.com/api/v1/sink/trigger/http/app_abc123/webhook" \
-H "Authorization: Bearer your-secret-token" \
-d '{"data": "payload"}'

Requests without the correct token will receive a 401 Unauthorized response.

If no auth_token is set, the endpoint is publicly accessible. Use this for:

  • Webhooks from third-party services that can’t add custom headers
  • Development/testing environments

The sink waits up to 120 seconds for the Flow’s first generic_result and returns its payload as JSON. For example, a Flow that returns {"accepted": true} produces:

HTTP/1.1 200 OK
Content-Type: application/json
{"accepted":true}

The returned payload belongs to your Flow. Configure a Generic Event with a return value when the caller needs a result. Test the request above with that Event active before connecting an external service.

If execution ends without a result, the result stream fails, or the result wait expires, the hosted endpoint returns an acknowledgement:

{"triggered":true,"run_id":"run_xyz","message":"Event triggered"}

The desktop endpoint instead returns the plain text Event triggered when no result arrives. HTTP 200 alone does not prove the Flow completed successfully. Inspect the run and its logs; do not automatically retry a request that may already have produced effects. A reverse proxy or caller can impose a shorter timeout than the sink’s result wait.

For progress events, use the Event invocation API: POST /api/v1/apps/{app_id}/events/{event_id}/invoke. The SDKs expose it as triggerEvent() and trigger_event(). Their asynchronous invocation methods return a run ID and poll token for longer work.

Receive webhooks from external services like GitHub, Stripe, or Slack:

{
"path": "/github-webhook",
"method": "POST",
"auth_token": null
}

Create a custom API endpoint for your application:

{
"path": "/api/v1/process",
"method": "POST",
"auth_token": "secret-api-key"
}

Handle form submissions from a website:

{
"path": "/submit-form",
"method": "POST",
"auth_token": null
}
Status CodeDescription
200 OKRequest accepted, execution started
401 UnauthorizedInvalid or missing auth token
404 Not FoundNo matching sink found for path
500 Internal Server ErrorExecution dispatch failed
  1. Use descriptive paths: /webhook/github/issues is better than /hook1
  2. Enable authentication for production endpoints
  3. Use HTTPS in production for encrypted communication
  4. Monitor execution logs to track incoming requests
  5. Set up rate limiting at the infrastructure level if needed