REST API - Webhooks#
Outbound HTTP notifications with HMAC-signed deliveries.
| Endpoint | Method | Description |
|---|---|---|
/projects/{id}/webhooks | GET | List webhooks |
/projects/{id}/webhooks | POST | Create a webhook |
/projects/{id}/webhooks/{webhookID} | PATCH | Update a webhook |
/projects/{id}/webhooks/{webhookID} | DELETE | Delete a webhook |
/projects/{id}/webhooks/{webhookID}/deliveries | GET | List deliveries |
/projects/{id}/webhooks/{webhookID}/send | POST | Send a test delivery |
/projects/{id}/webhooks/{webhookID}/deliveries/{deliveryID}/retry | POST | Retry a delivery |
Create:
{
"name": "order.created",
"url": "https://myapp.com/hooks/orders",
"events": ["order.created"],
"secret": "signing-secret"
}
JSONDelivery headers#
Every delivery includes:
| Header | Value |
|---|---|
X-Afribase-Event | The event name |
X-Afribase-Delivery | Delivery id |
X-Afribase-Signature | sha256=<hex> HMAC of the body with the webhook secret |
Verifying a delivery#
import { createHmac, timingSafeEqual } from 'node:crypto';
function verifyWebhook(rawBody: string, signatureHeader: string, secret: string): boolean {
const expected = createHmac('sha256', secret).update(rawBody).digest('hex');
const a = Buffer.from(signatureHeader.replace(/^sha256=/, ''), 'hex');
const b = Buffer.from(expected, 'hex');
return a.length === b.length && timingSafeEqual(a, b);
}
TypeScriptSecurity#
- Accepts the project API key (or a project-user session)
- Scoped keys:
webhooks:read,webhooks:write