Webhooks
Deliver event notifications to your HTTP endpoints with retries.
Webhooks allow you to receive HTTP callbacks when events occur in your Snaapi application. Configure webhook subscriptions with event pattern matching, custom headers, field filtering, and automatic retry with exponential backoff.
Set Up Your First Webhook
Create a webhook subscription via the Webhooks tab in the API builder or by sending a POST request to the admin API.
Send a POST request with your subscription details. Here is a complete curl example:
curl -X POST https://your-api.snaapi.cloud/admin/webhooks \ -H "Content-Type: application/json" \ -H "Authorization: Bearer <admin-token>" \ -d '{ "name": "Notify on new posts", "url": "https://example.com/hooks/snaapi", "eventPattern": "posts.created", "enabled": true, "headers": { "Authorization": "Bearer my-receiver-secret" } }'Choose an event pattern to control which events trigger the webhook. Use
posts.createdfor a single event type,posts.*for all events on a resource, or*for everything. See Event Patterns below.Receive events at your endpoint. When a matching event occurs, Snaapi sends a POST request to your URL with a JSON payload like this:
{ "id": "event-uuid", "event": { "type": "posts.created", "resource": "posts", "resourceId": "post-123", "createdAt": "2026-01-01T00:00:00Z", "data": { "old": null, "new": { "id": "post-123", "title": "Hello World" }, "changes": { "added": ["id", "title"], "updated": [], "removed": [] } } }, "delivery": { "id": "delivery-uuid", "attempt": 1 } }Respond with any 2xx status code to acknowledge receipt. Failed deliveries are retried automatically with exponential backoff.
Subscriptions
A webhook subscription defines where and how event notifications are delivered:
| Field | Type | Description |
|---|---|---|
id |
string |
UUID identifier |
name |
string |
Display name (1 to 255 characters) |
url |
string |
Delivery URL (max 2048 characters) |
eventPattern |
string |
Pattern to match events |
headers |
JSON object or null |
Custom HTTP headers to include |
enabled |
boolean |
Whether the webhook is active |
retryConfig |
retry settings or null |
Custom retry configuration |
fieldIds |
array of strings or null |
Field IDs to include in the payload |
createdAt |
string |
ISO 8601 creation timestamp |
updatedAt |
string |
ISO 8601 last-updated timestamp |
Event Patterns
Event patterns use wildcards to match one or more event types:
| Pattern | Matches |
|---|---|
* |
All events from all resources |
posts.* |
All events for the posts resource |
*.created |
All created events across all resources |
posts.created |
Only posts.created events |
Pattern names must match the regex ^[a-zA-Z0-9_.*]+$.
Custom Headers
Add custom HTTP headers to webhook deliveries for authentication or routing:
{
"headers": {
"Authorization": "Bearer my-secret-token",
"X-Custom-Header": "custom-value"
}
}
The following headers are always included automatically:
| Header | Value |
|---|---|
Content-Type |
application/json |
User-Agent |
Snaapi-Webhooks/1.0 |
X-Snaapi-Event |
Event type (e.g., posts.created) |
X-Snaapi-Event-Id |
Event UUID |
X-Snaapi-Delivery-Id |
Delivery UUID |
X-Snaapi-Delivery-Attempt |
Attempt number |
Field Filtering
Use fieldIds to limit which fields are included in the webhook payload. When
specified, only the listed fields (by ID) are included in a fields object:
{
"fields": {
"title": {
"id": "field-id",
"type": "string",
"value": "Hello World"
}
}
}
If fieldIds is null or omitted, no fields object is included in the
payload.
Webhook Payload
The full payload delivered to your endpoint:
{
"id": "event-uuid",
"event": {
"type": "posts.created",
"resource": "posts",
"resourceId": "post-123",
"createdAt": "2026-01-01T00:00:00Z",
"data": {
"old": null,
"new": { "id": "post-123", "title": "Hello World" },
"changes": { "added": ["id", "title"], "updated": [], "removed": [] }
},
"sessionVariables": { "userId": "user-1", "role": "editor" },
"traceContext": { "traceId": "abc", "requestId": "req-1" }
},
"delivery": {
"id": "delivery-uuid",
"attempt": 1
}
}
Delivery timeout is 30 seconds.
Retry Configuration
Webhooks use exponential backoff for failed deliveries. Customize retry behavior per webhook or use the defaults:
| Property | Type | Min | Max | Default |
|---|---|---|---|---|
maxAttempts |
number |
1 | 100 | 5 |
backoffMultiplier |
number |
1 | 10 | 2 |
initialDelayMs |
number |
100 ms | 60,000 ms | 1,000 ms |
maxDelayMs |
number |
1,000 ms | 3,600,000 ms | 300,000 ms |
The delay between retries is calculated as:
delay = min(initialDelayMs * backoffMultiplier ^ (attempt - 1), maxDelayMs)
Delivery Tracking
Each webhook delivery attempt is recorded as a WebhookDelivery:
| Field | Type | Description |
|---|---|---|
id |
string |
Delivery UUID |
webhookId |
string |
Parent webhook ID |
eventId |
string |
Associated event ID |
status |
string |
pending, success, or failed |
httpStatus |
number or null |
HTTP response status code (100 to 599) |
requestPayload |
string |
JSON request body sent |
responseBody |
string or null |
Response body received |
responseHeaders |
JSON object or null |
Response headers received |
error |
string or null |
Error message (if failed) |
deliveredAt |
string or null |
Timestamp of successful delivery |
attemptNumber |
number |
Attempt number (starts at 1) |
nextRetryAt |
string or null |
Scheduled time for next retry |
createdAt |
string |
ISO 8601 creation timestamp |
Delivery Statuses
| Status | Description |
|---|---|
pending |
Delivery is queued or awaiting retry |
success |
Endpoint responded with a successful HTTP status |
failed |
All retry attempts exhausted or a non-retryable error occurred |