Skip to content

Serving an HTTP Endpoint

This tutorial is the inbound counterpart to Polling An HTTP API: a job that listens for HTTP requests with the http-server input, processes each request as an event, and — when the caller needs a real answer — returns an explicit status and body with the response-complete output.

A minimal listener binds an address and path and emits one event per request:

input:
http-server:
address: 127.0.0.1:8085
path: /v1/ingest
json: true
source-ip-field: client_ip
  • json: true parses the request body as JSON into the event.
  • path restricts the listener to one route; requests elsewhere are not accepted.
  • source-ip-field records the caller address for auditing.

By default the listener acknowledges requests immediately (immediate mode): the caller gets a quick acceptance while the pipeline processes the event asynchronously. That is the right shape for fire-and-forget ingestion.

When the caller must learn the outcome — a webhook that needs a meaningful status code, an API that returns a computed result — switch to wait-for-workflow and bound the wait:

input:
http-server:
address: 127.0.0.1:8085
path: /v1/ingest
json: true
response:
mode: wait-for-workflow
timeout-seconds: 8
timeout-status-code: 503
timeout-body: '{"error":"processing timeout"}'
body-max-bytes: 65536

The request now stays open until the event reaches a response-complete output or the timeout fires. Pick timeout-seconds from the caller’s patience, not your processing hopes: many webhook providers fail a delivery after about 10 seconds and do not automatically retry it, so answering by 8 seconds — even with a 503 — leaves margin and keeps the failure visible on their side.

In wait-for-workflow mode, every event from the listener must reach a response-complete output. Compute the outcome, set the status and body as fields, and finish:

actions:
- java-script:
source: |
function transform(event) {
if (!event.json || typeof event.json !== "object") {
event.response_status = 400;
event.response_body = JSON.stringify({ error: "malformed payload" });
return event;
}
if (event.json.type !== "order.created") {
event.response_status = 204;
event.response_body = "";
return event;
}
// ... durable handling of the accepted event goes here ...
event.response_status = 202;
event.response_body = JSON.stringify({ accepted: true });
return event;
}
output:
response-complete:
status-code-field: response_status
content-type: application/json
body:
field:
field: response_body

This single-job shape returns a different status per outcome — for example 202 accepted, 204 ignored, 400 malformed — from one terminal output. A common four-lane contract for authenticated webhooks adds 401 for a failed authentication check, decided before the payload is parsed or acted on.

Two more rules keep the contract honest:

  • Answer 202 only after the work is durable. If acceptance means “queued for processing”, complete the response after the durable handoff succeeds — not before — so a crash cannot acknowledge work that was lost. If the handoff fails, let the timeout return 503: the caller’s delivery record then correctly shows a failure to retry or investigate.
  • Expect replays. Webhook deliveries can repeat or arrive out of order. Deduplicate on a stable identity from the payload (an event or run ID), not on the delivery attempt.

In a multi-job workflow, the same rules apply per branch: route outcomes with conditional dispatch (see Routing and Fan-out) and terminate every lane — accepted, ignored, rejected — in its own response-complete. The synchronous-response context travels with the event, and on-missing-context: ignore lets a shared tail also serve events that did not originate from a waiting caller.

  1. Run the job and send a request: curl -i -X POST 127.0.0.1:8085/v1/ingest -d '{"type":"order.created"}'
  2. Confirm each outcome returns its intended status, and that an intentionally slow or dropped event returns the timeout status — before a real caller finds out for you.
  3. Stage and deploy per Deploying jobs, pinning the job to the worker your proxy targets (see Placement and Scaling).