Webhooks (api/webhook)
A webhook subscription tells Agility to send an HTTP request to a URL you control whenever
something you care about happens. It is the push alternative to polling
query.v1 on a timer.
Subscriptions can be as broad or as narrow as you like: every Story status change in the instance, or only status changes on Stories in one project that are owned by one person.
How It Fits Together
A subscription has two halves:
- Where to deliver — the
url, an optionalauthorizationHeader, an optionalsecretfor payload signing, and awebhookIdyou choose to identify it. - What to deliver — an
eventTypesarray. Each entry describes a class of change using the same vocabulary as a query:from,attributes,filter,with,userContextandselect.
When a matching change happens, Agility POSTs a JSON body describing the event — who did it,
what changed, and a projection of the asset shaped by your select.
Operations
| Operation | Endpoint |
|---|---|
| Create a subscription | POST ~/api/webhook |
| Query subscriptions | GET ~/api/webhook |
| Update a subscription | POST ~/api/webhook/:id |
| Delete a subscription | POST ~/api/webhook/delete/:id |
| Check delivery status | GET ~/api/webhook/status/:id |
Supporting reference:
- Event types — how to describe what you want to be notified about
- Webhook payload — what arrives at your endpoint, and how to verify it
POST endpoints, including deleteThere is no PUT, PATCH or DELETE verb anywhere in this API. Update is a POST to the
subscription URL, and delete is a POST to .../api/webhook/delete/:id — the id is in the
path after the word delete. This is unusual, it is deliberate, and sending
DELETE ~/api/webhook/:id will get you a 405. See delete.
Permissions
Every endpoint in this API requires the ManageConfig privilege — the same administrative
privilege that governs instance configuration. Webhook subscriptions are an instance-level
integration surface, not a per-user one.
Instance Limits and Configuration
| Limit | Default | Effect |
|---|---|---|
| Maximum enabled subscriptions | unlimited | Creating past the limit fails. |
| Delivery retry attempts | 5 | Attempts per delivery — see retries and automatic disabling. |
These are instance configuration, adjustable by an administrator on on-premise installations.
The original reference stated that "in the first release of webhook subscriptions, your instance
can have up to 5 enabled webhook subscriptions at a time". That restriction has since been
lifted: MaxActiveSubscriptions now defaults to unlimited and the cap only applies where an
administrator has explicitly configured one.
If you do hit a configured cap, creation fails with a message naming the limit. Check the
setting rather than assuming the number is 5. The unrelated 5 that is still real is the
retry count.
Webhooks can also be disabled instance-wide. When they are, every endpoint in this section
returns 404 rather than an explanatory error — a blanket 404 from a correctly-formed request
usually means the feature is switched off, not that your subscription is missing.
Delivery Semantics
Understand these before you build against webhooks:
- Non-
200means failure. Responding with anything other than200 OKcounts as a failed delivery. Return200as soon as you have durably accepted the payload; do your processing afterwards. - Repeated failure eventually disables the subscription — through the retry and
probation model below. If a webhook has "stopped
working", check its
retryCountand its delivery receipts first. - Order is not guaranteed. Events may arrive out of order. Every event carries a
sequenceIdso you can reorder them yourself. Do not infer ordering from arrival time. - Delivery is at-least-once in effect. A retry after a response you actually processed will
redeliver the event. Make your handler idempotent, keyed on
webhookIdplussequenceId. - Your endpoint must be reachable from the Agility instance. For cloud-hosted instances that means publicly routable, or reachable through whatever egress path your instance is configured with.
Retries and Automatic Disabling
Two separate mechanisms, often conflated:
Retries happen per delivery. Each delivery is attempted up to 5 times (default), with exponential backoff starting at 5 seconds — so the gaps run 5, 10, 20, 40, 80 seconds. A successful delivery resets the retry count to zero.
Disabling happens on probation. When a delivery exhausts its retries:
- The first exhausted delivery puts the subscription on probation (default 12 hours) and sends a failure-warning email to the owner.
- A successful delivery during probation clears it — with a recovery email. Nothing was lost but the failed deliveries themselves.
- A delivery that exhausts its retries after the probation window has elapsed — meaning the endpoint has been failing for the whole window — disables the subscription, with a final notification email.
A disabled subscription stops producing receipts; fix the receiver, then re-enable via update. The retry count, backoff quantum and probation length are configurable on on-premise instances — ask your administrator if your instance behaves differently from the defaults above.
Related Topics
- Event types
- Webhook payload
- Activity stream — the pull equivalent, for reading history
- Query API (query.v1) — the
selectandfiltervocabulary - API conventions