Skip to content

Webhooks

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.

Subscriptions

A webhook subscription defines where and how event notifications are delivered:

Field Type Description
id string UUID identifier
name string Display name (1–255 characters)
url string Delivery URL (max 2048 characters)
eventPattern string Pattern to match events
headers Record<string, string> | null Custom HTTP headers to include
enabled boolean Whether the webhook is active
retryConfig RetryConfig | null Custom retry configuration
fieldIds string[] | 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 | null HTTP response status code (100–599)
requestPayload string JSON request body sent
responseBody string | null Response body received
responseHeaders Record<string, string> | null Response headers received
error string | null Error message (if failed)
deliveredAt string | null Timestamp of successful delivery
attemptNumber number Attempt number (starts at 1)
nextRetryAt string | 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