Skip to main content

Webhook event reference

Rule-line delivers a terminal webhook event to a job's resolved destination after a run reaches run.succeeded or run.failed. Queued/active run state is never delivered — poll GET /jobs/{id} for that. An API-triggered test run (test: true) sends the SAME event shape, with test: true set and no business-data mutation.

Event body​

FieldMeaning
eventIdThe stable identity of this terminal event. The SAME value across every automatic and manual delivery attempt — use it for deduplication. Never the run ID.
runIdThe run this event reports the terminal outcome of.
eventTypeEither run.succeeded or run.failed. Rule-line emits exactly these two terminal event types; queued/active run state is a polling-only concern and is never delivered.
eventCreatedAtThe immutable instant this event was created, at the run's first terminalization. Never changes across retries.
runCompletedAtThe immutable instant the underlying run reached its terminal outcome. Never changes across retries.
rulesetIdThe id of the ruleset version actually executed, selected through the active version at submission.
rulesetVersionThe exact ruleset version this run executed.
requestedRulesetIdThe activated version handle the caller named. It can differ from rulesetId after an approval or rollback; null when the run has no requested-version attribution. Immutable events created before this field was introduced can omit it. Poll responses call this member requestedRulesetVersionId.
localeThe run language frozen at submission: de for German or en for English. An omitted job locale uses the tenant default at submission; later settings changes do not change this event.
testTrue when the originating job was submitted with test: true. A test run makes no business-data mutations, but still sends the same terminal event shape.
outcomeEither succeeded or failed — the run's immutable terminal outcome.
resultThe ruleset's declared output on success, or the stable structured failure envelope on failure. Submitted JSON input and document content are never included. A large result is represented as a stable authenticated result-resource reference (href, sha256, sizeBytes) rather than being inlined.

Example values​

Illustrative full-length values for the identifier/URL/digest-shaped fields above — long enough to exercise this reference's own overflow and wrapping handling (UI-17/UI-18) in a real table, not just in prose.

FieldExample
eventId018f2c1a-9e3b-7c9a-8b0e-4f2a6d1c5e7b
destinationUrlUsedhttps://integrations.example-customer-tenant.example.com/webhooks/rule-line/incoming-terminal-events
result.sha2564f8b2c9a1d6e3f705c8a2b9d1e4f6a3c8b0d2e5f7a9c1b3d6e8f0a2c4b6d8e0f
Rule-Line-Signature headert=1780012345,v1=c1a2b3d4e5f60718293a4b5c6d7e8f90a1b2c3d4e5f60718293a4b5c6d7e8f90,v1=90f8e7d6c5b4a392817069584736251403f2e1d0c9b8a796857463524130f2e

Signing​

Every delivery attempt is signed with HMAC-SHA256 over ${timestamp}.${exactBodyBytes} (the raw, byte-exact request body — never a re-serialized copy) and sent in the Rule-Line-Signature header as t=<unix-seconds>,v1=<hex>.

During a destination secret rotation's overlap window, the header carries BOTH signatures — the CURRENT (active) secret's signature always first, then the previous secret's: t=<unix-seconds>,v1=<activeHex>,v1=<previousHex>. A receiver holding either secret can verify the delivery; accept a match against ANY v1 value present, not only the first.

Delivery outcome and retries​

Any HTTP response in the 2xx range acknowledges delivery. A redirect, a timeout, a transport-level error, and every non-2xx status are all treated as an unsuccessful attempt and retried — including a 4xx response.

One automatic delivery cycle makes up to 10 total attempts over roughly 72 hours, with exponential backoff and jitter:

AttemptNominal delay since previous attemptWorst case (with jitter)
2~300sup to ~345s
3~900sup to ~1035s
4~2700sup to ~3105s
5~8100sup to ~9315s
6~24300sup to ~27945s
7~43200sup to ~49680s
8~43200sup to ~49680s
9~43200sup to ~49680s
10~43200sup to ~49680s

Manual retry​

After a delivery cycle exhausts its attempts, an authorized user can manually retry it. A manual retry starts a fresh 10-attempt cycle for the SAME immutable event — it redelivers the exact same event body to the destination's CURRENT URL using its CURRENT active signing secret. The eventId never changes, and the underlying job is never resubmitted or re-evaluated: a retry is a delivery operation only, never a run operation. Contrast this with submitting an identical new POST /jobs request, which always creates and meters an independent second run.

Delivery attempt fields​

Every attempt in GET /runs/{runId}/delivery's attempts array:

FieldPresenceType
attemptLabelrequiredstring
attemptNumberrequiredinteger
cycleNumberrequiredinteger
destinationUrlUsedrequiredstring or null
httpStatusrequiredinteger or null
initiatedByrequired"system" | "manual"
latencyMsrequiredinteger or null
nextAttemptAtrequiredstring or null
requestPreviewrequiredstring or null
responsePreviewrequiredstring or null
secretVersionUsedrequiredstring (uuid) or null
sentAtrequiredstring
statusrequired"due" | "claimed" | "succeeded" | "failed" | "exhausted"
transportErrorrequiredstring or null