Webhook Ingestion Contract
Webhook-triggered automations expose a unique, public HTTPS endpoint that external systems (your PSA, RMM, alerting stack, Zapier, and so on) POST to. This page is the full contract for anyone configuring a sender: the URL model, authentication, optional request signing, payload handling, limits, every response code you can receive, and the receipt log that records each delivery.
The endpoint
Each webhook automation gets a unique URL of the form:
POST https://<automations-host>/webhooks/{automationId}/{webhookSecret}
Copy the complete URL from the automation's webhook configuration panel in the portal — don't construct it by hand. The secret embedded in the URL path is the primary authentication: anyone with the full URL can trigger the automation (subject to the limits below), so treat it like a password.
Authentication: two independent secrets
| Secret | Where it lives | Purpose |
|---|---|---|
| URL secret | Embedded in the webhook URL path | Primary auth. Compared in constant time; wrong secret → 401. |
| Signing secret | Shown in the configuration panel; used by your sender to sign request bodies | Optional per-request body integrity (HMAC). |
Both secrets are 32 random bytes, hex-encoded (64 hex characters). They are generated when the automation is provisioned as (or switched to) a webhook trigger. Switching the automation away from the webhook trigger preserves both secrets, so the URL still works if you switch back.
Optional request signing (HMAC-SHA256)
To protect against body tampering, your sender can sign each request:
- Compute
HMAC-SHA256(rawRequestBody, signingSecret)and hex-encode it (lowercase). - Send it in the header:
X-StackJack-Signature: sha256=<hex>. A bare 64-character hex value without thesha256=prefix is also accepted. Any other algorithm prefix (e.g.sha384=) is rejected.
Signature semantics:
- No header sent → verification is skipped (signing is opt-in per request).
- Header sent, signature wrong → 401 with support code
SJ-WH-SIG-INVALID. The receipt log records header/expected lengths, never digest values. - Header sent, but the automation has no signing secret yet (it predates signing support) → 401 with support code
SJ-WH-SIG-MISSING-SECRET. Rotate the webhook secrets once to provision a signing secret. StackJack deliberately rejects rather than silently accepting an unverifiable "signed" request.
Rotating secrets
The Rotate action regenerates both secrets at once. The old URL and old signing secret stop working immediately — update every sender when you rotate.
Payload handling
Choose how much of the request body reaches the agent via the automation's payload mode:
| Mode | What the agent receives |
|---|---|
| None | Nothing — the webhook is a pure "go" signal. |
| Full context | The entire raw request body. |
| Selected fields | A JSON object containing only the fields you list as dotted paths ($.ticket.id, $.alert.severity). Simple object paths only — no array indices or wildcards. Keys in the result are the original path expressions. If the body isn't valid JSON or no paths match, the agent receives no payload. |
Size limits
- Transport cap: 64 KB raw body, absolute. Larger requests are rejected.
- Per-automation payload cap: after payload-mode filtering, the payload must fit the automation's configured limit — default 32 KB, configurable up to the 64 KB transport ceiling. Exceeding it → 413.
Rate limit
Each automation accepts at most 10 webhook invocations per minute (sliding window). Beyond that, deliveries receive 429 and no run starts. This is separate from the platform-wide execution-slot limit.
Response codes (sender's reference)
| Status | Meaning | Body / headers | Retry? |
|---|---|---|---|
| 202 | Run accepted and started | { "runId": "...", "status": "..." } |
— |
| 400 | Automation is not configured for webhook triggers | Error message | No — fix configuration |
| 401 | Wrong URL secret, or signature problem | Signature failures include supportCode (SJ-WH-SIG-INVALID / SJ-WH-SIG-MISSING-SECRET) |
No — fix secret/signature |
| 402 | Out of credits — the run was refused at pre-flight | { "error": "insufficient_credits", "runId": "...", "status": "...", "retryable": false } (no Retry-After) |
No — top up credits |
| 404 | Unknown, inactive, or archived automation — or automations are disabled for the tenant (deliberately indistinguishable) | Empty | No |
| 413 | Body over 64 KB, or filtered payload over the automation's cap | Error message with the limit | No — shrink payload |
| 429 | Rate limit exceeded, or all platform execution slots busy (capacity_exceeded, retryable: true) |
Capacity responses include Retry-After: 30 |
Yes — back off and retry |
| 500 | The run failed to start due to a platform error | { "error": "Failed to start run" } |
Yes — retry with backoff |
| 503 | The run was created but its background monitor failed to launch | { "error": "launch_failed", "runId": "...", "status": "...", "retryable": true }, Retry-After: 30 |
Yes — honor Retry-After |
StackJack never queues or replays webhook deliveries. Any non-202 outcome means no run started; retries are entirely your sender's responsibility. Note also that there is no dedup — two accepted deliveries produce two runs.
The webhook receipt log
Every delivery attempt that reaches a live automation is recorded in that automation's webhook receipt log, visible in the portal (StackJack staff can see a mirror for support). Deliveries that 404 because the automation ID is unknown, inactive, or archived are deliberately not logged, so internet scanner noise can't flood your log. (A 404 caused by automations being disabled for your tenant is logged, as TenantDisabled.)
Each receipt records:
| Field | Notes |
|---|---|
| Received at | UTC timestamp |
| Outcome | One of: Accepted, TenantDisabled, WrongTriggerType, InvalidSecret, InvalidSignature, RateLimited, PayloadTooLarge, CapacityExceeded, OrchestrationFailed, CreditExhausted (402), LaunchFailed (503) |
| HTTP status returned | What your sender saw |
| Remote IP | The request's source IP address as observed by StackJack |
| User agent | Truncated to 256 characters |
| Payload bytes received | Raw body size, before payload-mode filtering |
| Run | Link to the run created (only for Accepted) |
| Detail | Redacted reason text — never contains secrets or signature digests |
Retention: receipts are currently kept indefinitely — there is no automatic purge. The portal's log view shows the most recent receipts (up to 500 per query).
Troubleshooting checklist
- Getting 404? Confirm the automation is active and not archived, and that you copied the full current URL (a rotation changes it). A 404 can also mean automations are disabled for your tenant — contact StackJack support.
- Getting 401 with no signature header? Your URL secret is stale — re-copy the URL.
- Getting
SJ-WH-SIG-MISSING-SECRET? Rotate the secrets once to provision a signing secret, then update the sender with the new values. - Getting 429s? Check whether you're over 10/minute for this automation (receipt shows
RateLimited) or the platform is at capacity (CapacityExceeded— honorRetry-After). - Agent didn't receive expected data? Check the payload mode and, for selected fields, that your dotted paths match the actual JSON structure — non-matching paths are silently omitted.