Skip to main content

Webhook trigger reference

Every field, header, status code, and error returned by the webhook trigger node, with concrete examples.

Overview

The webhook trigger fires a workflow whenever an external system sends an HTTP request to a unique URL that TaskJuice mints when you add the trigger to your workflow. This page documents every field you can configure, every response your callers will see — including the synchronous response modes that let a workflow author the reply — and every limit you need to design around.

If this is your first time building a webhook trigger, start with the quickstart instead — it walks through the minimum setup with a working curl example.

Webhook URL format

When you add a webhook trigger to a workflow, TaskJuice generates a unique URL of this shape:

https://api.taskjuice.ai/webhooks/<endpoint-token>

The endpoint-token is a 36-character UUID v4. It is the only credential that proves a request can reach your workflow, so treat it like a password:

  • Never paste it into public chat, screenshots, or version control
  • Rotate it (regenerate the trigger) if it leaks
  • Restrict where you store it just like you'd restrict an API key

The token is independent of your workflow ID and your subscription ID. Rotating it invalidates the previous URL and breaks any external system still calling the old one.

Where to find your URL

Open your workflow in the editor, click the webhook trigger node, and look for the Webhook URL field at the top of the configuration panel. Click the copy button to copy it to your clipboard.

Allowed HTTP methods

The webhook trigger accepts only GET and POST requests. Every other method returns 405 Method Not Allowed with an Allow header listing the supported methods.

MethodSupportedNotes
GETYesUse when the upstream system carries data in query parameters or headers, not a body. HMAC authentication is not available for GET because there is no body to sign.
POSTYesThe default for almost every webhook integration. Required for HMAC authentication.
PUT, PATCH, DELETE, HEAD, OPTIONS, TRACENoReturns 405 method not allowed. The Allow response header lists the supported methods.

Request body

POST requests can carry a body. TaskJuice parses the body once and exposes it to your workflow as $trigger.

Content type

By default a webhook trigger accepts any content type — the body is decoded according to the incoming Content-Type header. JSON bodies (application/json) are parsed as JSON; form-encoded bodies (application/x-www-form-urlencoded) are decoded into a nested object (see Form-encoded bodies below); multipart and binary bodies extract their files (exposed as file references on $trigger); an unrecognized body that is not valid JSON falls back to raw.

If you set a content-type allowlist under the trigger's Advanced Settings → Request Validation (leave it empty to accept any type), a request whose Content-Type is not on the list returns 415 Unsupported Media Type.

How the body becomes $trigger

TaskJuice normalizes every parsed body into an object before exposing it to your workflow:

Body shape receivedWhat $trigger containsExample
Plain JSON objectThe object itself, unchanged{"event":"test"} → $trigger.event is "test"
Top-level JSON arrayWrapped under items[{"id":1},{"id":2}] → $trigger.items is the array
Top-level primitive (string, number, boolean)Wrapped under value42 → $trigger.value is 42
Form-encoded bodyDecoded into a nested objecttype=subscribe&contact[id]=1 → $trigger.contact.id is "1"
Non-form body that fails to parse as JSONWrapped under raw as a string"not json" under text/plain → $trigger.raw is the literal string
Empty body (POST with no payload)The request returns 200 empty and no workflow run fires—

The wrapping is consistent so your downstream nodes can always assume $trigger is an object. If you need to iterate over a top-level array, point a Loop node at $trigger.items.

Headers are not exposed to your workflow

HTTP headers from the incoming request are used for authentication and (optionally) deduplication, but they are not included in $trigger. If you need to read a value that the upstream system only sends in a header, ask the upstream system to put it in the body instead.

Form-encoded bodies

When the incoming Content-Type is application/x-www-form-urlencoded, TaskJuice decodes the body into an object using the same bracket-notation convention as qs, Rack, and PHP — the format that providers like ActiveCampaign, Mailchimp, and Twilio send:

  • Values are always strings. qty=42 becomes the string "42", not the number 42. Cast downstream in a Smart Field or JSONata expression if you need a number or boolean.
  • Bracket keys nest. contact[id]=1 becomes $trigger.contact.id.
  • Repeated keys and [] build arrays. tag=a&tag=b and tag[]=a&tag[]=b both become $trigger.tag = ["a","b"].
  • Numeric indices become object keys, not array slots. contact[fields][3]=x nests as contact → fields → a string key "3", never an array. In the mapping picker these segments are quoted for you; in hand-written JSONata, wrap a numeric segment in backticks — e.g. $trigger.contact.fields.`3`.

Authentication modes

You configure authentication on the trigger node from the Authentication Type dropdown. Five modes are supported:

ModeWhen to use itGenerated by TaskJuice
noneInternal-only webhooks where the URL itself is the only credential and the network path is trusted. Acceptable for prototyping; not acceptable for production traffic from third parties.Nothing
bearerUpstream system sends Authorization: Bearer <token>. Use for first-party webhooks from your own services or for providers that support bearer auth.A bearer token, copyable from the trigger panel
headerUpstream system sends a custom header (for example x-api-key: <secret>). Use when the provider documents a specific header name.A header secret, copyable from the trigger panel
hmac-sha256Upstream system signs the raw request body with a shared secret using HMAC-SHA256. Use for providers like GitHub, Stripe, and Slack.A signing secret, copyable from the trigger panel
hmac-sha512Same as HMAC-SHA256 but uses SHA-512. Use only when the provider requires SHA-512.A signing secret, copyable from the trigger panel

HMAC modes are not available when the trigger only allows GET, because there is no body to sign.

For step-by-step setup of each mode, see the authentication guide.

Replay defense (HMAC only)

The Webhook trigger has no replay-defense settings. HMAC modes verify the signature over the raw request body and nothing else — no timestamp tolerance, no nonce tracking — so a captured signed request passes verification if it is sent again. To keep a replayed or retried delivery from starting a second run, enable a deduplication strategy; Payload Hash collapses byte-identical replays within the window. App Webhook triggers verify each provider's own signing scheme where the provider offers one, and where the provider's signing recipe declares a timestamp tolerance TaskJuice enforces it automatically, with nothing to configure.

Deduplication fields

Deduplication prevents the same logical event from triggering more than one workflow run within a configured time window. You configure it under the Advanced Settings → Deduplication section. The default is Disabled.

StrategyWhen to use itRequired fields
Disabled (none)Every request triggers a run, even if the upstream system retries. Use only when your workflow is fully idempotent.none
Event ID (eventId)The upstream system sends a stable event ID in the body. TaskJuice extracts the field at $.eventId (or $.id) and uses it as the dedup key.none
Payload Hash (payloadHash)TaskJuice hashes the entire raw body and uses the hash as the dedup key. Catches byte-identical retries.none
Header Value (headerValue)TaskJuice reads a specific header (for example X-Idempotency-Key) and uses its value as the dedup key.Header Name
Expression (expression)You provide a JSONPath expression that resolves to a value in the body. The resolved value becomes the dedup key.Key Expression
FieldTypeDefaultDescription
Deduplication StrategyenumnoneOne of the five strategies above.
Window (seconds)integer, 1-86,4003600The time window during which a duplicate dedup key suppresses additional workflow runs. Maximum is 24 hours.
Header Namestring—Required when strategy is Header Value. The exact header name to read.
Key Expressionstring—Required when strategy is Expression. A JSONPath expression like $.data.id.

Under a synchronous response mode, a retry that deduplication collapses is acknowledged with 200 and the canonical {"received":true,"request_id":"…"} body plus the header X-TaskJuice-Deduplicated: true. The original computed response is not replayed — the header tells an integrating caller that this delivery was collapsed onto an earlier one. Without a deduplication strategy, a caller's retry is a new request: it starts a second run and receives a second computed response.

App Webhook triggers — the per-app trigger nodes from the integrations catalog — have no deduplication settings because TaskJuice deduplicates provider retries for them automatically: a retried delivery is acknowledged, starts no second run, and appears under Monitoring → Activity as a Deduplicated row on the trigger's subscription. When the provider stamps each delivery with a unique id, retries are collapsed for up to three days, the longest retry schedule any supported provider documents. For a provider that sends no such id but documents a short retry schedule, such as MailerLite, TaskJuice recognises a retry by each event's exact content instead, for a shorter window sized to that provider's schedule; the app's page says how long. The match is per event, so an event identical to one already received within that window is treated as a repeat even when it arrives in a different delivery. Other providers that send no per-delivery id keep at-least-once behaviour.

Pre-execution filter fields

The pre-execution filter lets you accept the request but skip running the workflow when the body doesn't match a condition. Configure it under Advanced Settings → Pre-Execution Filter.

FieldTypeDefaultDescription
Pre-Execution FiltertoggleoffEnables or disables filtering for this trigger.
Modeinclude | excludeincludeinclude runs the workflow only when the expression evaluates to true. exclude skips the workflow when the expression evaluates to true.
Expressionstring—A JSONPath boolean expression evaluated against the parsed body. Example: $.data.status == 'active'.

A filtered request still returns 200, so the upstream system doesn't retry. The filter happens before the workflow run is created, so filtered events do not appear in your run history.

PII redaction fields

PII redaction replaces matching field values in the parsed body with a redaction marker before the workflow runs. Field names are matched against your regex patterns case-insensitively. Configure it under Advanced Settings → PII Redaction.

FieldTypeDefaultDescription
PII RedactiontoggleoffEnables or disables redaction for this trigger.
Field patternsstring[][]A list of regular expressions, one per line. Field names matching any pattern are redacted.
LimitValue
Maximum patterns50
Maximum length per pattern200 characters
Pattern formatAny valid JavaScript regular expression

Redaction applies before the body reaches $trigger, so your workflow expressions never see the original values.

Response modes

The Response mode setting on the trigger node (under Advanced Settings → Request Validation) decides what your caller receives and when. There are three modes, plus one the Phone Call trigger pins for you:

Response modeValueWhat the caller receivesWhen it is sent
Immediate ACKimmediate_ack200 OK with {"received":true,"request_id":"…"}. The default.As soon as the request passes validation, before any node runs
Respond noderespond_nodeThe status, headers, and body authored by a Respond node in the workflow.When the Respond node runs, within the response timeout
Last node outputlast_node200 OK with the terminal step's output as JSON.When the last node finishes, within the response timeout
Stream (NDJSON)streaming200 OK at once, then one JSON line per event as the workflow produces it — see Streaming.Begins immediately; lines arrive until the stream ends
Phone callphone_callThe answer document that connects the caller to the workflow's Voice Agent.When the Voice Agent runs, within a 10-second budget

The two buffered synchronous modes answer within the response timeout — 25 seconds by default; where your environment allows it, you can raise it per trigger.

The phone_call row is not a choice: the Twilio Phone Call trigger pins it, because a phone call has exactly one way to be answered. Its budget is shorter than the other two — telephony providers give an answer document about 15 seconds before they treat the call as failed, and TaskJuice answers at 10 with headroom to spare. A slow step between the trigger and the Voice Agent is therefore a real risk, and the publish bar warns you when it sees one.

Immediate ACK is the async model: TaskJuice acknowledges, then runs the workflow in the background. The two synchronous modes hold the HTTP connection open while the workflow runs, so the caller receives a computed response — the shape a chatbot platform, a voice gateway expecting TwiML, or a form backend needs.

Where synchronous modes are available

Synchronous response modes apply to the generic Webhook trigger only. App Webhook triggers — the per-app trigger nodes from the integrations catalog — must acknowledge the provider immediately and always use Immediate ACK. If the two synchronous options are absent from the Response mode dropdown, they are not yet enabled for your environment. An older value, sync_validate, is retired: a trigger that still carries it behaves as Immediate ACK.

Immediate ACK

When TaskJuice accepts and dispatches a webhook event in Immediate ACK mode, it returns a 200 OK with this exact body:

{
  "received": true,
  "request_id": "550e8400-e29b-41d4-a716-446655440000"
}

The response also carries an X-Request-Id header with the same UUID:

HTTP/1.1 200 OK
Content-Type: application/json
X-Request-Id: 550e8400-e29b-41d4-a716-446655440000

{"received":true,"request_id":"550e8400-e29b-41d4-a716-446655440000"}

The request_id is a per-request correlation token. It identifies a single delivery attempt and is the join key you use to find the corresponding entry in your run history or to reference when contacting support. The same UUID appears in the X-Request-Id header so tools that prefer headers (most observability platforms) pick it up automatically.

When the request is technically valid but produces no workflow run (an empty GET with no query parameters, for example), the response is the same 200 body. There is no separate "empty" status leaked to the caller; your run history shows whether a run was created.

Respond node

In Respond node mode the workflow answers the caller from a Respond system node placed anywhere downstream of the trigger. TaskJuice runs the nodes between the trigger and the Respond node, sends the response the moment the Respond node runs, and keeps running any nodes after it in the background.

The Respond node's configuration is the response:

FieldTypeDefaultDescription
Status codeinteger200200–299 or 400–599. Informational (1xx) and redirect (3xx) codes are refused — a Respond node never redirects.
Content typejson | text | xml | emptyjsonSelects the body source and the wire Content-Type: json → application/json; charset=utf-8, text → text/plain; charset=utf-8, xml → text/xml; charset=utf-8, empty → no body and no Content-Type.
Bodymapped input or template—json: the node's mapped input, authored on the Output Mapping surface like any other node. text and xml: a body template with {{ }} markers resolved from $trigger, $steps, and the other expression aliases. empty: nothing.
Headersname → value map{}Up to 16 headers. Allowed: Cache-Control, Content-Language, Content-Disposition, Vary, and any custom X- header except X-Request-Id and X-TaskJuice-*. Everything else is refused at publish and at runtime (see Forbidden headers below).

Rules that apply to every Respond node:

  • Redaction. A json body is passed through the same sensitive-key redaction as run data before it is serialised: a value under one of the platform's known credential keys — token, access_token, refresh_token, api_key, secret, client_secret, password, credentials, authorization — reaches the caller as [REDACTED]. Echoing $trigger back as JSON strips those keys; any other key, and any text or xml template, is sent exactly as authored.
  • Size. The serialised body must fit in 256 KiB. A larger body fails the Respond node with RESPOND_BODY_TOO_LARGE, the caller receives 500 internal error, and the run viewer shows the size — a truncated document is never sent.
  • X-Request-Id is always the platform's. It is set last, from the request's own id, so no authored header can override it.
  • Forbidden headers. Set-Cookie, Location, Content-Type (derived from the content type), Content-Length, Transfer-Encoding, Connection, Keep-Alive, Upgrade, TE, Trailer, Server, and any Proxy-* or Access-Control-* header. Header names must be valid HTTP tokens of at most 64 characters; values must be visible ASCII, at most 1 KiB, with no line breaks. The node panel reports the exact refusal inline, and publish refuses the same names with the same message.
  • First Respond wins. The request is answered by the first Respond node the run reaches; the rest of the run continues in the background, so a second Respond node sends nothing, still succeeds, and records no-transport in its output. The same no-transport outcome is recorded by a Respond node that runs in a node test, in Run now, or in a workflow whose trigger is on Immediate ACK.
  • No response point reached. If the run completes without ever running a Respond node, the caller receives the Immediate ACK body, 200 {"received":true,"request_id":"…"}.

A worked example for a voice gateway: content type xml, status 200, body template <Response><Say>{{$steps.reply.data.text}}</Say></Response> answers 200, Content-Type: text/xml; charset=utf-8, X-Request-Id: <request id>, and the rendered TwiML document.

Which nodes may run before a Respond node

Because the caller is waiting, every node on a path from the trigger to a Respond node must be able to finish inside the request. Publishing refuses — naming the node — any node that pauses the run on such a path: Delay, wait-for-event nodes, Form nodes, and approval or human-input steps.

What else may run before the Respond node depends on your environment. Where webhooks are served with extended synchronous responses (the Response timeout field is shown on the trigger), these also run before the answer: Call Workflow (await and for-each), Parallel and its join, Loop in parallel mode, AI agents in durable mode, and heavy (file-handling) steps. Elsewhere, publishing refuses them on a path to the Respond node too, with the message "… pauses or fans out the workflow …".

A node of one of these kinds elsewhere in the graph — on a branch that does not lead to the Respond node — is fine: if the run takes that branch, TaskJuice hands the run to the background and the caller receives 202 (see below). A Respond node placed after another Respond node, or in a workflow whose trigger is on Immediate ACK, publishes with a warning: it will only ever run as a no-op.

Last node output

In Last node output mode there is no Respond node. TaskJuice runs the whole workflow and answers 200 OK with the output of the terminal step as JSON:

HTTP/1.1 200 OK
Content-Type: application/json; charset=utf-8
X-Request-Id: 550e8400-e29b-41d4-a716-446655440000

{"greeting":"Hello Ada","token":"[REDACTED]"}
  • What "terminal step output" is. The body is the data member of the step that ends the run — exactly what $steps.<that step>.data resolves to for a downstream node. The step's meta stays in the run viewer and is not sent. If the step's output has no data member, the whole output is sent.
  • Which step is terminal. A step with no outgoing connection ends the run. A step whose outgoing conditions select no path also ends the run, and answers with its own output. The response comes from the step that ends the run — the last step to complete. When a Branch or Switch leads to several leaves, that is the leaf on the path the run actually took, and the arms not taken contribute nothing. Where webhooks are served with extended synchronous responses, fan-out may also run before the answer (see Which nodes may run before a Respond node); the caller is then answered when the whole run completes, with the output of whichever leaf finished last, and the other leaves contribute nothing.
  • Fixed envelope. Status 200, Content-Type: application/json; charset=utf-8, X-Request-Id, no authorable headers. The body goes through the same redaction and 256 KiB bound as a json Respond node. A terminal output over the bound answers 500 internal error with the run reading completed — the step is never failed after the fact.
  • No Respond node allowed. The two modes are mutually exclusive: a workflow on Last node output that contains a Respond node is refused at publish, naming the node. Remove it, or switch the trigger to Respond node mode.
  • Whole-graph eligibility. Every node reachable from the trigger — not only the nodes on one path — must be free of the kinds that may not run before a Respond node (see Which nodes may run before a Respond node — on an environment with extended responses, only the pausing kinds), because any of them could run inside the request.

Streaming (NDJSON)

In Stream (NDJSON) mode the caller receives 200 OK with Content-Type: application/x-ndjson; charset=utf-8 and Cache-Control: no-store immediately, and then one JSON object per line as the workflow produces output. The mode is offered only where your environment streams webhook responses; if the option is absent from the Response mode dropdown, it is not available there.

Every line has a type:

typeFieldsMeaning
beginrunIdAlways the first line, exactly once.
itemnodeId, dataOutput as it is produced: each Respond node's body, and an AI agent's text as the model writes it (data: {iteration, text}).
heartbeat—Sent every 30 seconds while nothing else flows, so idle connections stay open. Ignore it.
endrunId, statusThe stream finished. Nothing follows it.
errorreason: deadline, handed_off, run_failedThe stream ended early. deadline: the response timeout passed. handed_off: the run moved to the background. run_failed: a step failed before the stream ended. In every case nothing follows it, and for deadline and handed_off the run keeps going in the background.
{"type":"begin","runId":"7a6c…"}
{"type":"item","nodeId":"agent-1","data":{"iteration":0,"text":"Looking that up"}}
{"type":"item","nodeId":"respond-1","data":{"ok":true}}
{"type":"end","runId":"7a6c…","status":"completed"}

Rules for streaming runs:

  • Respond nodes write lines, not responses. Each Respond node the run reaches writes its body as one item line; their status codes and headers are ignored (the 200 left at begin). Turn on a Respond node's End stream toggle to end the stream right after its line — the rest of the workflow keeps running in the background. Without an End stream node, the stream ends with end when the run completes.
  • One line is at most 256 KiB. A larger body is replaced by {"truncated":true} under its nodeId; the run itself is unaffected.
  • Nothing may pause the run before an End stream node. Publishing refuses a Delay, wait, Form or approval step on a path to a Respond node whose End stream is on, and — when no node has End stream on — anywhere the run can reach.
  • If your client disconnects, the run continues in the background.
  • The stream lasts at most 870 seconds, the longest response timeout streaming allows.

Response timeout

Where your environment allows synchronous answers longer than 25 seconds, the trigger shows a Response timeout (seconds) field for Respond node, Last node output and Stream (NDJSON). It is stored as responseTimeoutMs:

ModeDefaultRangeAt the timeout
Respond node, Last node output25 s1–280 s504 {"error":"gateway timeout","request_id":"…"}; the run continues
Stream (NDJSON)25 s1–870 s{"type":"error","reason":"deadline"} ends the stream; the run continues

A value above the mode's maximum is clamped when you switch to a mode with a lower maximum. In an environment without extended responses the field is hidden and the budget is 25 seconds whatever is stored.

Timing, capacity, and hand-offs

Both synchronous modes share the same envelope of guarantees:

SituationStatusBodyWhat happens to the run
The response point (Respond node or terminal step) is reached within the budgetauthored / 200authored / the terminal step's dataContinues in the background after a Respond node; completes
The response timeout (25 seconds by default) elapses before the response point. The budget is measured from the moment TaskJuice received the request; a node already running is never interrupted.504{"error":"gateway timeout","request_id":"…"}Continues in the background and completes; a Respond node reached later records no-transport
A node parks the run (an approval gate, a retry with back-off, a connection request), a heavy-lane or fan-out node is reached, an operator pauses or cancels the run, the request is too large to hand to the in-line executor, the platform could not run the request in-line (a throttled or faulted executor), or the trigger's response mode was changed after the workflow was published — from Immediate ACK to a synchronous mode, or between Respond node and Last node output202{"received":true,"request_id":"…"}Handed to the background: accepted, but no synchronous answer could be authored. 202 says exactly that; 200 would claim completion. The run continues in the background. A mode change takes effect only on republish: republish a workflow whose trigger mode changed after it was published, and until then every request is answered 202.
A node fails before the response point500{"error":"internal error","request_id":"…"}The run fails and the error trigger fires, as in Immediate ACK
The run completes without reaching a Respond node (Respond node mode only)200{"received":true,"request_id":"…"}Completed
5 synchronous requests are already in flight for the workspace (the sixth is refused)503 + Retry-After: 2{"error":"service unavailable","request_id":"…"}Nothing ran; the request is safe to retry after two seconds

The request_id on every one of these responses is the same join key described under Using the request_id, so a 504 or 202 can be matched to its run in the run history.

Error responses

Every error response shares the same shape:

{
  "error": "<short generic message>",
  "request_id": "<uuid>"
}

The HTTP status code carries the actual meaning. The body's error field is a short, lowercase, generic phrase chosen from a fixed list. The same string is returned for every reason a given status class can fire — for example, every 401 says "authentication failed" regardless of whether the signature was wrong or the header was missing. This is intentional: a more specific message would tell an attacker which guess was closer to correct.

Statuserror valueWhat it meansWhat to check
400bad requestThe request was malformed at the protocol level (missing route parameters, invalid URL).Verify your URL path matches the format above.
401authentication failedThe signature, token, or header value didn't match what the trigger expects.Re-verify your secret and the auth mode you configured. The exact reason is hidden by design.
404not foundThe endpoint token doesn't correspond to any trigger.Confirm the URL token from your trigger configuration. The trigger may have been rotated or the workflow archived.
405method not allowedYou sent a method other than GET or POST (or the trigger only allows one of them).Check the Allow header on the response — it lists the supported methods.
409duplicate requestReserved. A delivery that deduplication collapses is acknowledged with 200 and no run (plus X-TaskJuice-Deduplicated: true under a synchronous mode), so this status is not returned today.Nothing — a duplicate is a 200; check the run history to confirm only one run was created.
413payload too largeThe request body exceeded the configured maximum size.Reduce the payload size or contact the trigger owner to raise the limit.
415unsupported media typeThe trigger has a content-type allowlist configured and the request's Content-Type was not on it.Send a Content-Type on the allowlist, or clear the allowlist under Advanced Settings → Request Validation to accept any type.
422validation failedThe pre-execution filter ran and rejected the event.Check the filter expression and the body — the request was authentic but didn't match the filter.
500internal errorSomething went wrong on TaskJuice's side — or, under a synchronous response mode, a node failed before the response point or the authored body exceeded 256 KiB.Capture the request_id from the response and check the run in your run history before contacting support.
503service unavailableSynchronous modes only: the workspace already has 5 synchronous requests in flight. Nothing ran.Retry after the Retry-After header's value (2 seconds).
504gateway timeoutSynchronous modes only: the response timeout elapsed before the response point. The run continues.Shorten the path to the Respond node or terminal step, or switch the trigger to Immediate ACK and poll the run.

For 5xx responses, the body never includes any details about the underlying failure — no exception class names, no stack traces, no service names. The request_id is the only identifier you should report when filing a support ticket.

Using the request_id

The request_id returned in every response is the join key that connects three places:

  1. The HTTP response the upstream system received (body field and X-Request-Id header)
  2. The run history entry in your TaskJuice dashboard for that delivery attempt
  3. The internal logs TaskJuice support uses to investigate failures

When you contact support about a failed delivery, include the request_id exactly as it appeared in the response. Without it, support has to search by approximate timestamp, which is slower and less reliable.

The request_id is generated fresh per request. It does not identify your workflow, your subscription, or your tenant — only the specific HTTP attempt. Sharing one is safe.

Accessing trigger data in workflow expressions

Inside your workflow, every node downstream of the trigger can read the request body via the $trigger expression alias. The shape of $trigger follows the body normalization rules from the Request body section.

Body the upstream sentExpression to read it
{"event":"checkout.completed","amount":4999}$trigger.event → "checkout.completed"
{"event":"checkout.completed","amount":4999}$trigger.amount → 4999
[{"id":"a"},{"id":"b"},{"id":"c"}]$trigger.items → the array; iterate with a Loop node pointed at $trigger.items
42 (a primitive)$trigger.value → 42
"not json" (parse failure)$trigger.raw → the literal string

$trigger does not contain headers. If you need a value the upstream system only sends in a header, ask the upstream system to put it in the body.

Limits

Hard limits enforced by the platform. These are not configurable from the workflow editor.

LimitValue
Endpoint token length36 characters (UUID v4)
Default request body size limit1,048,576 bytes (1 MB)
Allowed HTTP methodsGET, POST only
Deduplication window1 to 86,400 seconds (1 second to 24 hours)
Maximum PII redaction patterns50 per trigger
Maximum length per PII pattern200 characters
Synchronous response budgetThe response timeout (25 seconds by default; up to 280 s, or 870 s streaming, where extended responses are available) from receipt of the request
Synchronous requests in flight5 per workspace
Authored response body256 KiB (serialised UTF-8)
Authored response headers16 per Respond node; names ≤ 64 characters, values ≤ 1 KiB

The body size limit is enforced before authentication, so an oversized payload is rejected with 413 without consuming any auth verification work.

Was this helpful?