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, 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.

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

The Content-Type header is required for POST requests with a body. The default acceptable type is application/json. If you have configured a content-type allowlist (set by the platform team in the trigger definition), requests with any other content type return 415 Unsupported Media Type.

How the body becomes $trigger

TaskJuice normalizes every parsed body into an object before exposing it to your workflow. Three rules apply:

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
Body that fails to parse as JSONWrapped under raw as a string"not json"$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.

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 fields (HMAC only)

When you select hmac-sha256 or hmac-sha512, three additional fields appear under the Replay Defense section. All three are optional, and you can set them independently:

FieldTypeDefaultDescription
Timestamp HeaderstringunsetThe header name where the upstream system sends the request timestamp (for example X-Timestamp for Stripe-style signing). When set, TaskJuice rejects requests whose timestamp falls outside the tolerance window.
Tolerance (seconds)integer, 1-3600unset (no enforcement)The maximum age of a request, in seconds. A request older than this is rejected with 401. Only enforced when Timestamp Header is also set.
Nonce HeaderstringunsetThe header name where the upstream system sends a unique nonce per request. When set, TaskJuice tracks recently-seen nonces and rejects duplicates within the tolerance window.

A typical Stripe-style configuration uses Timestamp Header = Stripe-Signature-Timestamp, Tolerance = 300, and no nonce header.

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 SettingsDeduplication 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 NamestringRequired when strategy is Header Value. The exact header name to read.
Key ExpressionstringRequired when strategy is Expression. A JSONPath expression like $.data.id.

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 SettingsPre-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.
ExpressionstringA 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 SettingsPII 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.

Successful response

When TaskJuice accepts and dispatches a webhook event, 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 200 with this body:

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

The same shape — there is no separate "empty" status leaked to the caller. Your run history shows whether a run was created.

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, the timestamp was expired, 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 requestA previous request within the dedup window had the same dedup key.Expected behaviour when deduplication is enabled. Wait until the dedup window expires or change the dedup key.
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 Content-Type header was not in the trigger's content-type allowlist.Send application/json or check the configured allowlist.
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.Capture the request_id from the response and contact support.

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.amount4999
[{"id":"a"},{"id":"b"},{"id":"c"}]$trigger.items → the array; iterate with a Loop node pointed at $trigger.items
42 (a primitive)$trigger.value42
"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)
Replay tolerance window (HMAC)1 to 3,600 seconds (1 second to 1 hour)
Maximum PII redaction patterns50 per trigger
Maximum length per PII pattern200 characters

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?