Create a Subscription
Request
POST ~/api/webhook
Payload
{
"url": "https://externalsystem.com",
"authorizationHeader": "Optional HTTP Authorization Header to send with each webhook",
"secret": "Optional shared secret used to sign each webhook",
"webhookId": "Webhook identifier",
"enabled": true,
"description": "Short description of the webhook subscription",
"eventTypes": []
}
| Field | Type | Required | Description |
|---|---|---|---|
url | string | yes | Where deliveries are POSTed. Must be reachable from the Agility instance. |
webhookId | string | yes | Your identifier for this subscription. Echoed in every delivery. Make it meaningful and unique. |
eventTypes | array | no | What to be notified about. See event types. Omitting it is accepted — validation is skipped when the key is absent — but a subscription with no event types is not useful. |
notificationEmails | array | no | Addresses notified about delivery problems for this subscription. |
enabled | boolean | no | Whether the subscription is live. Create disabled to stage a configuration. |
description | string | no | Free text: where this goes and why. Worth filling in — it is what a future administrator will read. |
authorizationHeader | string | no | Sent verbatim as the Authorization header on every delivery. |
secret | string | no | Shared secret used to HMAC-sign each delivery. See verifying the payload. |
api/webhook validates the request body strictly and rejects any property that is not
a member of the model, answering 400 with { "errorMessage": … }.
This applies to both create and update, and it is worth knowing because it is the opposite of how several other Agility surfaces behave — the Bulk API, for instance, tolerates keys it does not recognise. Do not assume a payload that works elsewhere will be accepted here.
Example
curl -X POST "https://{host}/{instance}/api/webhook" \
-H "Authorization: Bearer <access-token>" \
-H "Content-Type: application/json" \
-H "Accept: application/json" \
-d '{
"url": "https://externalsystem.example.com/hooks/agility",
"webhookId": "story-status-to-slack",
"description": "Notifies #delivery when a Story status changes in the Sandbox project",
"enabled": true,
"authorizationHeader": "Bearer s3cr3t-token-the-receiver-checks",
"secret": "a-long-random-string-used-for-hmac",
"eventTypes": [
{
"type": "AssetChanged",
"from": "Story",
"attributes": ["Status"],
"filter": ["Scope=$Scope"],
"with": { "$Scope": "Scope:0" },
"select": ["Name", "Number", "Status.Name", "Owners.Name"]
}
]
}'
Response
{
"id": "336d997f-d9fa-4612-80e8-9f41a4b41352",
"webhookId": "Webhook identifier",
"url": "https://externalsystem.com",
"description": "Short description of the webhook subscription",
"enabled": true,
"eventTypes": [],
"createdAt": "2018-09-27T20:28:41.3829451Z",
"updatedAt": "2018-09-27T20:28:41.3829451Z",
"createdBy": "Member:20"
}
| Field | Description |
|---|---|
id | Server-assigned UUID. This — not webhookId — is what update, delete and status take. |
webhookId | The identifier you supplied. |
createdBy | Oid token of the member who created the subscription. |
The create response does not carry delivery-health fields — a subscription
that has never fired has no delivery history. For retryCount and
lastResponseAt, use Query subscriptions or
Delivery status.
Note that authorizationHeader and secret are not echoed back. They are write-only.
After Creating
- Confirm it is live with query.
- Make a change that should match, then check delivery status to see what your endpoint actually returned.
Creating with "enabled": false first, then enabling via update once
the receiver is deployed, avoids burning retry attempts against an endpoint that is not up yet.
Related Topics
- Event types
- Webhook payload
- Query subscriptions
- Webhooks overview — permissions and instance limits