Skip to main content
Webhooks push real-time event notifications to your server as settlements progress. This is the recommended way to track settlement progress instead of polling for most states.

How webhooks work

KeyStone’s settlement engine dispatches webhooks to all platforms involved in a settlement: each time an engine run advances a settlement and leaves it in a new state, one event fires, named for the state the run ended in. Intermediate states passed through in the same run are skipped, and states written directly by on-chain events or operator actions do not emit their own event - see the event catalog for exactly what fires and how to track the rest.

Local development

During development, your server runs on localhost which KeyStone can’t reach. The KeyStone CLI solves this by forwarding webhooks to your local server:
This creates a temporary endpoint, polls for events, and forwards them to your local server in real-time. No ngrok or tunneling tools needed. See the CLI documentation for details.

Setting up a webhook endpoint

1. Register the endpoint

Create a webhook endpoint in the KeyStone Dashboard under Settings > Webhooks. You need to provide:
  • URL - Your HTTPS endpoint that will receive webhook deliveries
  • Event types - Which events to subscribe to (see patterns below)
The webhook secret is displayed once at creation time. Store it securely - you need it to verify webhook signatures. You can also register endpoints via the API:

2. Event type patterns

Webhook events

Event names are settlement.state. followed by the lowercased state name. The events that fire today: There are no separate settlement.compliance.* webhook events - compliance outcomes surface through the state events above. States written directly by on-chain outcomes or operators (SETTLED, ROLLED_BACK, TIMED_OUT, MANUAL_REVIEW, and initial INSTRUCTED) currently emit no webhook of their own - track those by polling the settlement or its events endpoint; see states without their own webhook.

Webhook payload format

Every webhook delivery includes:
The payload is intentionally minimal - it identifies the settlement and its new state. Fetch the full settlement with GET /v1/settlements/{settlement_id} when your handler needs more detail.

Verifying signatures

Every webhook delivery includes an X-Keystone-Signature header containing an HMAC-SHA256 hex digest of the request body.
Always use constant-time comparison to prevent timing attacks. Never use === or == for signature verification.

Secret rotation

Rotate your webhook secret in the KeyStone Dashboard under Settings > Webhooks by clicking Rotate Secret on the endpoint, or via the API:
During the 24-hour grace period:
  • Deliveries include both X-Keystone-Signature (new secret) and X-Keystone-Signature-Previous (old secret)
  • Your server should verify against both headers
  • After 24 hours, only the new secret is used

Testing

Send a test ping from the KeyStone Dashboard under Settings > Webhooks, or via the API:

Best practices

  1. Return 200 quickly - Process webhooks asynchronously. Return a 200 status immediately and handle the event in a background job.
  2. Handle duplicates - Webhooks may be delivered more than once. Use the settlement ID plus state to make your handler idempotent.
  3. Verify signatures - Always verify the HMAC signature before processing. Reject unsigned or invalid requests.
  4. Monitor delivery logs - Check delivery logs in the KeyStone Dashboard or via the API:

Retry policy

Failed deliveries (non-2xx response or timeout) are retried up to 3 times in quick succession with short, jittered backoff (a Retry-After header is honored on 429 responses). After that the delivery is marked as failed in the delivery log - there is no delayed redelivery queue, so reconcile missed events by fetching the settlement’s current state.

Webhook Event Catalog

See every event type with exact payloads and handler examples.

CLI Webhook Forwarding

Forward webhooks to localhost during development.