Skip to main content
Webhooks push real-time event notifications to your server whenever a settlement changes state. This is the recommended way to track settlement progress instead of polling.

Setting up a webhook endpoint

1. Register the endpoint

Create a webhook endpoint in the KeyStone Dashboard under Settings > Webhooks. You’ll 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’ll need it to verify webhook signatures. You can also register endpoints via the API:
curl -X POST https://api.keystoneos.xyz/v1/platforms/me/webhooks \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://your-platform.com/webhooks/keystone",
    "event_types": ["settlement.*"]
  }'

2. Event type patterns

PatternMatches
*All events
settlement.*All settlement events
settlement.state.finalizedOnly finalization events
settlement.confirmation_requiredCounterparty confirmation requests

Webhook payload format

Every webhook delivery includes:
{
  "event": "settlement.state.compliance_cleared",
  "data": {
    "settlement_id": "stl-...",
    "state": "COMPLIANCE_CLEARED",
    "previous_state": "COMPLIANCE_CHECKING",
    "settlement_type": "single_platform",
    "timestamp": "2026-03-16T12:00:00Z"
  }
}

Verifying signatures

Every webhook delivery includes an X-Keystone-Signature header containing an HMAC-SHA256 hex digest of the request body.
import hashlib
import hmac

def verify_webhook(body: bytes, signature: str, secret: str) -> bool:
    expected = hmac.new(
        secret.encode(),
        body,
        hashlib.sha256,
    ).hexdigest()
    return hmac.compare_digest(expected, signature)
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:
curl -X POST https://api.keystoneos.xyz/v1/platforms/me/webhooks/$WEBHOOK_ID/rotate-secret \
  -H "Authorization: Bearer $TOKEN"
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:
curl -X POST https://api.keystoneos.xyz/v1/platforms/me/webhooks/$WEBHOOK_ID/test \
  -H "Authorization: Bearer $TOKEN"

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 event ID or settlement 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 under Settings > Webhooks (click an endpoint to see its delivery history), or via the API:
curl https://api.keystoneos.xyz/v1/platforms/me/webhooks/$WEBHOOK_ID/delivery-logs \
  -H "Authorization: Bearer $TOKEN"

Retry policy

Failed deliveries (non-2xx response or timeout) are retried with exponential backoff. After all retries are exhausted, the delivery is marked as failed in the delivery log.