Automation
Webhooks
Configure an outbound webhook in Apiable: set the URL, the events to subscribe to, an optional secret and headers. Apiable signs every payload with the Standard Webhooks scheme.
A webhook tells your systems when something changes in Apiable. You register an endpoint with a URL and the events it should receive, and Apiable sends a signed HTTP POST to that URL each time one of those events fires. You manage webhooks through the Platform API.
How do you configure a webhook?
Create a webhook through the Platform API by sending a POST with the URL to call and the events to subscribe to. The secret and headers are optional. Apiable generates a signing secret if you do not supply one.
/api/webhooks A webhook configuration has these fields:
| Field | Required | What it is |
|---|---|---|
| url | Yes | The endpoint Apiable sends the POST to. It can be any URL that accepts an HTTP POST. |
| events | Yes | The list of event types this webhook receives. Apiable only posts when one of these fires. |
| whsec | No | The signing secret, base64-encoded and prefixed whsec_. Apiable generates one between 24 and 64 bytes if you omit it. |
| headers | No | Extra HTTP headers to send with every request, for example an API key your endpoint checks. |
| authorization | No | A single Authorization header value. Deprecated; use headers instead. |
What events can a webhook subscribe to?
Nine event types, covering subscriptions, invoices, and scope grants. You list the ones a webhook should receive in its events field, and Apiable posts only for those.
| Event type | Fires when |
|---|---|
SUBSCRIPTION_CREATED | A developer creates a subscription to a plan. |
SUBSCRIPTION_CANCELLED | A subscription is cancelled. |
SUBSCRIPTION_CHANGED | A subscription changes. |
SUBSCRIPTION_AUTH_CHANGED | A subscription's authentication or credentials change. |
INVOICE_ATTENTION_REQUIRED | An invoice needs attention. |
SCOPE_GRANT_REQUESTED | A consumer requests a scope grant. |
SCOPE_GRANT_APPROVED | A scope grant request is approved. |
SCOPE_GRANT_DECLINED | A scope grant request is declined. |
SCOPE_GRANT_REVOKED | A scope grant is revoked. |
What does a webhook payload look like?
Each delivery is a JSON body that follows the Standard Webhooks spec. It carries the event type, a timestamp, the event data, an id, and an optional source URL. For a subscription event, data includes the subscription id, status, plan, and auth.
{
"id": "67040bcb1eb964694d999a68",
"type": "SUBSCRIPTION_CREATED",
"timestamp": "2026-06-07T10:15:30.123Z",
"data": {
"id": "664f1c2a9b1e4a0012ab34cd",
"status": "ACTIVE"
},
"source": "https://your-tenant.apiable.io/api/subscriptions/664f1c2a9b1e4a0012ab34cd"
}The type matches the event you subscribed to. The data object depends on the subject: subscription events add the id, status, plan, and any auth, while other events carry at least the subject id.
How does Apiable sign webhook payloads?
Apiable signs every payload with the Standard Webhooks scheme. It sends three headers and an HMAC-SHA256 signature computed with your secret, so your endpoint can confirm the request came from Apiable and was not changed.
Every delivery includes these headers:
| Header | What it carries |
|---|---|
webhook-id | A unique id for the message. |
webhook-timestamp | The send time as an integer unix timestamp, in seconds. |
webhook-signature | The signature, as a space-separated list of versioned signatures, each v1,<base64>. |
To verify a delivery, rebuild and compare the signature:
- Read
webhook-id,webhook-timestamp, andwebhook-signaturefrom the request headers. - Build the signed content as
{webhook-id}.{webhook-timestamp}.{raw-body}, joined with full stops. - Compute an HMAC-SHA256 over that content using your secret. The secret is base64-encoded after the
whsec_prefix; decode it to get the key bytes. - Base64-encode the HMAC result and compare it to the
v1value inwebhook-signature. - Reject the request if the
webhook-timestampis more than 5 minutes from now, to guard against replays.
How does Apiable retry a failed delivery?
Apiable treats 200, 201, 202, and 204 as success. Any other response, or an unreachable endpoint, is a failure. A failed delivery is retried on an hourly schedule, up to 3 attempts, then it stops.
Each attempt is recorded against the webhook as a delivery instance with one of four statuses:
| Status | Meaning |
|---|---|
PENDING | The delivery has not succeeded yet and is queued for a retry. |
SUCCESS | Your endpoint returned a 2xx. The delivery is complete and is not retried. |
ERROR | The delivery failed. It is retried hourly until it succeeds or reaches 3 attempts. |
SKIPPED | The event was not sent to this webhook. |
How do you see a webhook's delivery history?
Read a webhook's recent delivery records through the Platform API. The history endpoint returns the responses Apiable recorded for that webhook over the last 24 hours, including the status and body of each attempt.
/api/webhooks/{id}/history You can also send a test delivery to confirm your endpoint is reachable before you rely on real events. Apiable posts a signed payload with the type TEST_EVENT to the configured URL and returns the status and body it got back.
/api/webhooks/{id}/test Troubleshooting
Match what you see to the fix.
| What you see | What to do |
|---|---|
The create request is rejected with an invalid whsec error | Your secret must be base64-encoded, prefixed whsec_, and decode to 24 to 64 bytes. Omit whsec to let Apiable generate a valid one. |
Deliveries show status ERROR and keep retrying | Your endpoint did not return 200, 201, 202, or 204. Check the delivery history for the response Apiable received, and return a 2xx once you accept the event. |
| A delivery stopped retrying and never arrived | Apiable retries up to 3 times, then stops. Fix the endpoint, then update the webhook so future events deliver. |
| Your endpoint receives the POST but signature verification fails | Sign {webhook-id}.{webhook-timestamp}.{raw-body} with HMAC-SHA256 over the decoded secret, base64-encode it, and compare to the v1 value. Verify against the raw body, not a re-serialized one. |
| Verification fails with a timestamp error | The webhook-timestamp is outside the 5-minute tolerance. Check that your server clock is correct, then accept deliveries within the window. |
| The test delivery never reaches your endpoint | The /test call reports the status and body Apiable received. A connection error there means the URL is wrong or unreachable from Apiable. |