Register a webhook
An https URL on a public host, for a set of events. The signing secret is returned ONCE — record it now: it is never stored by us, so replaying this call with the same Idempotency-Key returns "secret": null rather than repeating it (rotate the secret if you lost it). Deliveries are POSTed within about a minute and retried on 1m / 5m / 30m / 2h / 12h.
Every delivery carries four headers: X-Triggr-Signature (see below), X-Triggr-Event (the event name), X-Triggr-Delivery-Id (the delivery row’s id) and User-Agent: Triggr-Webhooks/1.0. The body is a WebhookEnvelope.
Two ids, and they mean different things. The envelope’s id identifies the EVENT: it is unchanged across retries and across a redelivery (POST …/redeliver re-posts the original payload bytes), so it is your dedupe key. X-Triggr-Delivery-Id identifies the DELIVERY ROW: it is the same on every retry attempt of that delivery (attempts 1 to 5 all carry it), changes on a redelivery, and matches a row in GET …/deliveries — use it to correlate with the delivery history and in support conversations.
Verify X-Triggr-Signature: t=<unix>,v1=<hex HMAC-SHA256(secret, t + "." + rawBody)>, rejecting a t older than 5 minutes. The header may carry MORE THAN ONE v1 — for 24 hours after a secret rotation (POST …/rotate-secret) each delivery is signed with the new secret and the previous one — so accept it if ANY v1 matches.
A webhook whose deliveries keep exhausting their retries after 25 consecutive failures is disabled (re-enable it with POST …/enable once the endpoint is fixed); revoking the key that registered a webhook disables it too. Delivered and failed history is kept for 30 days. An event is delivered at most once per webhook unless you ask for it again with …/redeliver.
Catalogue changes — subscribe to these instead of re-reading the lists: form.created / form.updated / form.deleted, client.created / client.updated / client.deleted, and core_form.updated. They fire for a change made in any way — the Triggr app, this API, or Triggr’s AI assistant — and are sent typically within 30 seconds of the change (at most about 90 seconds), then retried on the schedule above. data is the object exactly as the list endpoint returns it now (Form, Client or CoreForm); for a *.deleted event it is { "id", "deletedAt" }. form.updated fires on any change to a form, including its fields (compare updatedAt); client.updated fires only when something in the Client object changed; core_form.updated when its enabled / availability / homepage settings or a client override changed. Core forms are a fixed catalogue, so they are never created or deleted. Each form and workflow also carries updatedAt, so after an outage longer than the retry schedule one list call tells you what changed.
Authorizations
Organisation API key. Scoped operations carry x-triggr-scope; the scopes themselves are described in x-triggr-scopes.
Headers
OPTIONAL — omit it and this operation behaves exactly as it always has. A unique value (a UUID) you choose per request. A retry with the same key and the same method, path and body within 24 hours gets the first response replayed (status and body, with Idempotent-Replayed: true) instead of running again; the same key with a different request is refused with 422. A 5xx is not stored, so that retry runs. A one-time credential is never stored: on a replay any secret is null, with an idempotentReplayNote explaining it.
1 - 255Body
*, execution.completed, execution.failed, approval.requested, approval.decided, approval.expired, manual_step.created, manual_step.completed, manual_step.cancelled, core.request.submitted, form.created, form.updated, form.deleted, core_form.updated, client.created, client.updated, client.deleted Response
Created
Present only on an Idempotency-Key replay whose original response carried a one-time credential: says that the value is shown only in the original response and how to issue a fresh one
The signing secret, shown ONCE. null on an Idempotency-Key replay — see idempotentReplayNote

