Webhooks API
It is possible to have the Atomic platform send updates to a configured webhook within your system, whenever an event occurs. These webhooks can be configured and tested via the Webhook API.
Subscribed URLs will be called via a PUT
or POST
request with payload data for the event.
Webhooks can be configured for any of the events listed in the analytics events section, for example card-dismissed
or card-published
. A webhook can be subscribed to many different events.
A credential role of workbench
is required to utilize the Webhooks API.
You can interact with the Webhooks API using Insomnia (follow the Insomnia instructions) or curl. When using curl, you'll need to set up your Authentication first.
Detailed specs and examples can be found in the Atomic API spec for the webhooks endpoint.
API endpoints
Subscribe to a webhook
Example of subscribing a url to the "card-publish" webhook:
PAYLOAD='{
"types": ["card-published", "card-completed"],
"url": "https://example.com/card-state-webhook",
"headers": {"My-Custom-Header": "123"}
}'
curl -X POST "$ATOMIC_API/v1/$ENVIRONMENT_ID/webhook" \
--header "Content-Type:application/json" \
--header "Authorization: Bearer $TOKEN" \
--data "$PAYLOAD" | jq
To create a webhook subscription for a specific card, the card and Action Flow ids can be specified in the payload:
PAYLOAD='{
"types": ["card-published"],
"url": "https://example.com/card-state-webhook",
"headers": {"My-Custom-Header": "123"},
"cardTemplateId": "1",
"actionFlowConfigId": "2"
}'
curl -X POST "$ATOMIC_API/v1/$ENVIRONMENT_ID/webhook" \
--header "Content-Type:application/json" \
--header "Authorization: Bearer $TOKEN" \
--data "$PAYLOAD" | jq
On success, subscription details are returned in the response body
{
"data": {
"id": "2nBrJUjz",
"types": ["card-published"],
"url": "https://example.com/card-state-webhook",
"headers": {"My-Custom-Header": "123"},
"secret": "0217309e-3c74-41b5-82e9-bd60e5db9bdb",
"created": "2019-08-28T00:22:36.950Z",
"updated": "2019-08-28T00:42:11.734Z"
}
}
List existing subscriptions
To list all webhook subscriptions, call the following endpoint:
WEBHOOKS=$(curl -X GET "$ATOMIC_API/v1/$ENVIRONMENT_ID/webhook" \
--header "Authorization: Bearer $TOKEN")
echo $WEBHOOKS | jq
Example response:
{
"data": [
{
// subscription details as above
},
...
]
}
Test a webhook subscription
Webhooks may be tested via API. The endpoint triggers a test event for a single webhook subscription, specified by passing in the webhook id:
curl -X POST "$ATOMIC_API/v1/$ENVIRONMENT_ID/webhook/$WEBHOOK_ID/test" \
--header "Content-Type:application/json" \
--header "Authorization: Bearer $TOKEN" | jq
The subscribed testing url (if any) should receive a request with a test payload.
Disable a webhook subscription
To disable a webhook url and cease receiving updates make a DELETE
request using the subscription's id.
WEBHOOK_ID="enter-webhook-id"
curl -X DELETE "$ATOMIC_API/v1/$ENVIRONMENT_ID/webhook/$WEBHOOK_ID" \
--header "Content-Type:application/json" \
--header "Authorization: Bearer $TOKEN" | jq
Once disabled, you can delete the subscription in the Workbench.
Example card status-change webhook payload
When the user actions a card, the card-complete webhook is triggered:
{
"requestId": "...",
"environmentId": "...",
"webhookId": "...",
"isBatched": false,
"data": {
"id": "...", // unique ID for this event
"analyticsEvent": "card-completed",
"endUserId": "...",
"timestamp": "2021-03-26T00:46:50.711Z",
"cardContext": {
"cardInstanceStatus": "completed",
"cardTemplateId": "...",
"cardTemplateName": "...",
"cardTemplateVersion": 1,
"cardTemplateSettings": {
"sendNotifications": false
},
"publishedAt": "2021-03-26T00:46:16.527Z",
"cardInstanceId": "1",
"previousStatus": "active"
},
"eventContext": {
"ip": "...",
"actionSource": "...",
"userLocalTimestamp": "2021-03-26T13:46:50.591+13:00"
},
"properties": {
"values": {...} // user input is found here
},
"sdkContext": {
"platform": "Web",
"sdkVersion": "0.15.0",
"sdkDevice": "...",
"sdkTimezone": "Pacific/Auckland",
"isDNDActive": false
},
"streamContext": {
"streamId": "1",
"streamName": "..."
},
"platformContext": {
"lifecycleId": "...",
"targetStreamIds": ["...", "..."],
"targetPlatforms": ["Web", "iOS", "Android"],
"flowInstanceId": "bb9c4ed5-d97c-49e7-be4c-97f9d88cbb9f",
"flowInvocationId": "caaa170d-0521-4dfa-903a-19f410480402",
"flowConfigId": "A9WBVx",
"triggerEventSource": "...",
"eventDetail": {
"today": "2021-02-27T11:00:00.000Z",
"myDate": "2021-02-28T11:00:00.000Z",
"dateShort": "2021-02-27T11:00:00.000Z",
"numberOfItems": "1"
},
"eventNotificationDetail": {...}
}
}
}
Verifying webhook payloads
Webhook requests are signed with an associated secret; your system should verify that the request originates from Atomic, and hasn't been tampered with, by checking the provided signature can be recreated using the payload and secret. Each webhook request has a vnd.io.atomic.signature
header which contains the signature. Your system should use a timing-safe comparison function rather than comparing the raw strings, to avoid timing attacks.
Example payload verification in node.js, using createHmac and timingSafeEqual:
import crypto from "crypto";
const secret = "<secret associated with this webhook>";
const body = "<request body>";
const requestSignature = "<vnd.io.atomic.signature header value>";
const signature = crypto
.createHmac("sha256", secret)
.update(body)
.digest("base64");
if (
signature.length === requestSignature.length &&
crypto.timingSafeEqual(Buffer.from(signature), Buffer.from(requestSignature))
) {
console.log("payload is safe");
} else {
console.log("payload is unsafe");
}
Webhook delivery retries
If your webhook endpoint is not available, or if it returns an http error status, then we will retry sending the request again after a short delay. This delay will back off exponentially with each successive failure, for up to 4 hours.
Updates which cannot be sent to your system are saved internally as analytic events and can be retrieved via the batched data API endpoint. Read how this can be achieved in the analytics overview.
If a webhook endpoint fails to return an http success code for 23 consecutive attempts, it will be automatically disabled. Disabled webhooks can be re-enabled in the Workbench.
The maximum number of webhook retries and whether or not to disable after failure can be configured.
We guarantee at-least-once delivery of webhooks, so in rare cases you may receive a payload twice. Your system should be idempotent or de-duplicate incoming events as needed using the unique id provided with each webhook payload.
Webhook authentication
A number of authentication methods can be configured for Webhooks via the Atomic Workbench. See Webhook credentials for more information.