apps/api/src/services/webhooks.ts — this reflects what actually fires, not what’s planned.
Envelope
Every event is delivered as a POST with this JSON envelope:X-Sly-Signature: t=<unix_ts>,v1=<hmac_sha256_hex>— verify thisX-Sly-Event-Id: evt_<uuid>— stable ID; dedupe in your handlerX-Sly-Delivery-Id: del_<uuid>— unique per delivery attemptX-Sly-Webhook-Id: wh_<uuid>— which subscription triggered this
Transfer events
data:
Settlement events
Fired when payouts transition through Circle (stablecoin → fiat) or other rails.data:
return and errorCode are only present for returned/failed states.
Batch events
For batch transfers and mass operations.data:
Reconciliation events
data for reconciliation.completed:
x402 events
data for x402.payment.completed:
AP2 events
data for ap2.mandate.executed:
ACP events
data:
Account events
data for account.balance.low:
System events
data for webhook.test:
Subscribing
- Specific events:
"transfer.completed" - Wildcards:
"transfer.*"(all transfer events) - Everything:
"*"(not recommended in production — high volume)
Enumerate supported events programmatically
Events in planning but NOT emitted yet
The following have been mentioned in platform roadmap docs but are not wired up in the current API. Don’t subscribe expecting to receive them:- Most
stream.*events (runway alerts, pause, resume, cancel) approval.*events — use polling + the approvals endpoints insteaddispute.*/refund.*as distinct events — currently surfaced throughtransfer.refundedand audit log; dedicated events plannedagent.*lifecycle events (tier upgrade, key rotation, etc.)quote.*,mpp.*,a2a.task.*funding.transaction.*,treasury.alert.*card.dispute.*
Delivery behavior recap
- At-least-once — dedupe by
X-Sly-Event-Id - Timeout — 10 seconds; respond fast, process async
- Retries — 1m → 5m → 15m → 1h → 24h, then DLQ
- Envelope always
{ id, type, timestamp, data }