How to set up webhook triggers
A webhook-triggered automation runs whenever an external system sends an HTTP POST to the automation's unique URL. This is how you wire PSA/RMM alerts, monitoring tools, or automation platforms…
Written By Christopher Scaminaci
Last updated 3 days ago
A webhook-triggered automation runs whenever an external system sends an HTTP POST to the automation's unique URL. This is how you wire PSA/RMM alerts, monitoring tools, or automation platforms (Zapier, n8n, Power Automate) into a StackJack automation.
Set up a webhook automation
- Create an automation (or edit an existing one) and choose the Webhook trigger.
- Pick a Payload mode (how much of the sender's request body reaches the agent — see below).
- Optionally set Max payload size (bytes). Leave blank for the server default of 32 KB; the hard ceiling is 65,536 bytes (64 KB).
- Save, then open the automation detail page. The Webhook card shows everything the sending system needs.
The webhook URL is a credential
The webhook URL has the form:
https://agents.stackjack.io/webhooks/<automation-id>/<secret>
The secret is embedded in the URL itself — anyone who has the URL can trigger your automation. Treat it like a password:
- Use the Copy button rather than transcribing it.
- Don't paste it into tickets, chat, or documentation.
- If it leaks, click Rotate secrets immediately.
Payload modes — how the body reaches your agent
Whatever payload survives filtering becomes the run's trigger payload — it is given to the agent as the context for that run, and you can see exactly what was received on the run's detail page in the Trigger payload card.
Payloads that exceed the size cap after filtering are rejected with HTTP 413 and no run starts.
Smart filters — starting a run only for the deliveries worth it
A smart filter is an optional judgement you add to a webhook trigger. Before any run starts, StackJack asks a specialist service a short question about the delivery and starts a run only when your conditions pass. Use it when the sender cannot narrow what it posts and you do not want a run — and its credits — for every message.
- It judges every delivery that reaches it. There is no sampling. The filter runs after deduplication: if a delivery started a run, a byte-identical resend inside the 60-second deduplication window is answered as a duplicate and is not judged again. A resend of a delivery the filter skipped is judged again, and so is any resend to an automation without deduplication.
- What you write. A provider and a model (
typesafeandjev-latest; both are required), one or more questions of the same three types a decision step uses — Noul (yes/no), Choice or Score — and at least one condition underrunWhen. When all of your conditions pass, the delivery starts a run. A filter with no condition is refused when you save. - It needs the payload. A filter judges the same filtered trigger payload the automation itself would receive, so an automation set to None — discard body cannot carry one; saving is refused and the editor offers to remove the filter. If a delivery arrives with no payload at all, it is not judged and the run starts.
- When the service cannot answer, your If no answer can be reached choice decides: Run (the default — the delivery starts a run as though there were no filter) or Skip.
- A skipped delivery is a success, not an error. The sender gets
200with{ "status": "filtered" }, so a well-behaved one does not retry it. No run is created and no run ID is returned, so the delivery costs no run credits. The filter's own judgement is a fast decision — see Fast Decisions and Your Own TypeSafe Key for what one costs. The response is deliberately the same whatever the filter decided — the sender is not the author. It is in the canonical webhook response table with every other status. - Steering attempts are flagged. StackJack flags payloads that try to steer the filter on the delivery's receipt, shown on the webhook receipts panel.
- The whole judgement is bounded at two seconds, including any retry. It cannot hold up your sender.
Every judgement is recorded and shown on the automation's webhook receipts panel, with what was asked and what came back. If StackJack cannot read an automation's stored filter, the Automations page marks that automation Not Ready. Fix or remove the filter in the builder.
Running a webhook automation from your AI assistant
A webhook automation with Expose to external AI harness turned on can also be invoked manually from your connected AI assistant via stackjack_run_agent — without waiting for its webhook sender. The assistant passes the payload as the call's context; the run records as a manual run and the payload is fenced exactly like a real inbound webhook body. So the assistant knows what to send, stackjack_list_agents discloses the automation's payload mode, its selected-field paths, and the optional Example payload you can set on the webhook trigger editor (documentation only — incoming webhooks are never validated against it). To retry a previous delivery after fixing the automation, pass that run's id as rerunOfRunId and its stored trigger payload is replayed as a new run; the run detail page's Re-run with this payload button does the same thing.
Optional request signing (HMAC)
Beyond the URL secret, you can have senders prove the body wasn't tampered with:
On the Webhook card, click Reveal next to Signing secret (it is masked by default) and copy it.
Configure the sender to compute
HMAC-SHA256(raw request body, signing secret)and send the resulting 32-byte digest as a header:X-StackJack-Signature: sha256=<hex digest>The header is optional — omit it and only the URL-secret check applies. If the header is present, an invalid signature is rejected with
401.
How the digest may be encoded
StackJack decodes the header back to the raw 32-byte digest before comparing, so the encoding your sender happens to use does not change the verdict. All of these are accepted:
The sha256= prefix is optional in front of any of them. Anything else — a different algorithm prefix, or a value that does not decode to exactly 32 bytes — fails closed with 401.
If you get an unexpected 401 on a signed request, a successfully persisted entry in the delivery log tells you which of three things went wrong: the header could not be parsed (its encoding is not one of the forms above), the digest did not match (the signing secret differs, or the sender signed something other than the exact raw body StackJack received), or the automation has no signing secret provisioned yet — click Rotate secrets once to provision one.
The Webhook card includes copy-paste curl examples — an unsigned one always, and a signed one that renders only after you click Reveal (so the secret never sits hidden on the page).
Rotating the secrets
Click Rotate secrets and confirm. Rotation generates a new URL secret and a new signing secret, and it takes effect immediately — the old URL stops working the moment you confirm, so update every external sender right away.
Delivery limits and response codes
- Rate limit: 10 webhook invocations per minute per automation. This check runs before signature verification and deduplication, so an otherwise-identical resend can get
429with no original run ID instead of a duplicate200. - Transport cap: request bodies over 64 KB are rejected.
- Durable capacity handling: if the delivery is accepted while execution capacity or the automation's one-at-a-time lease is busy, StackJack returns
202with a new run ID andstatus: "Queued". Do not retry that response; StackJack owns the queued work. - AI service overloaded: if the AI service (Anthropic) is overloaded when the run tries to start, StackJack can hold the run and return
202with a new run ID,status: "LaunchHeld", andheld: true. StackJack tries again automatically. Do not retry that response either. - Byte-identical redeliveries: new automations have raw-body deduplication enabled. If a resend reaches deduplication and matches a successfully persisted receipt inside the default 60-second window, it returns
200withduplicate: trueand the original run ID, and creates no second run. Rate limiting can stop the request first, and a failed receipt write leaves nothing to match. Existing automations were not backfilled and may retain no-dedup behavior. - Ambiguous
500: no run ID does not prove no run exists. APendingrun may already have been saved and can later recover and execute. Do not retry unconditionally: the endpoint provides no idempotency guarantee for this outcome, and a retry can duplicate work. - Never retry a
402. On this endpoint a402is a stable business refusal only the organization can clear — it is out of automation credits (error: "insufficient_credits"), or its Agent Runner plan ended and its own Anthropic key is no longer used for runs (error: "agent_runner_base_lapsed"). Neither carries aRetry-After, and both reportretryable: false. Contrast the429rate limit above and the503launch fault, which are retryable.
Use the canonical webhook response table for every status, response shape, and retry rule. See Triggers and Execution Guarantees for what happens to an accepted queued run after the response.
Webhook receipts (delivery log)
StackJack attempts to log application-level outcomes against a known, active automation. Receipt writes are best-effort, and a missing receipt does not prove that no request or run exists. The receipt list normally helps with delivery diagnosis, but a missing receipt does not prove that the sender never reached the automation or that no run exists.
Attempts against unknown, inactive, or archived automations get a 404 and are deliberately not submitted to the log. A request rejected by the web server before the webhook controller runs — for example, at the transport-size boundary — may also have no receipt. If an expected receipt is missing, keep the automation ID, approximate UTC time, sender address, and HTTP response for StackJack support.
- Inline panel: the automation detail page includes a collapsed Recent webhook receipts panel showing the last 20 receipts with a Refresh link.
- Full page: choose Webhook logs from a webhook automation's detail-page action row. The dedicated
/automations/<automation-id>/webhook-logspage shows up to 500 receipts with a limit selector (50 / 100 / 250 / 500) and a Refresh button.
Each receipt row shows: received time, outcome, the HTTP status returned to the sender, the sender's IP address, payload size in bytes, and a short detail string. Possible outcomes:
Requests aimed at an unknown automation ID are deliberately not submitted to the receipt log (internet scanner noise); the same applies to inactive and archived automations. A tenant-side kill switch (TenantDisabled) is normally submitted, subject to the same best-effort persistence described above.