Skip to main content
Webhooks let Sly push event notifications to your application — transfers completing, streams alerting, approvals being requested. Don’t poll; subscribe.

When to use webhooks vs. SSE

WebhooksSSE
DirectionSly POSTs to your URLAgent opens a persistent connection
ReachabilityYou need a public HTTPS URLAgent makes the outbound connection
Best forServer-side integrationsAgents running locally / sandboxed
DeliveryAt-least-once with retriesBest-effort with replay buffer
See persistent SSE for the agent-oriented alternative.

Create a subscription

curl -X POST https://api.getsly.ai/v1/webhooks \
  -H "Authorization: Bearer pk_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "url": "https://hooks.example.com/sly",
    "events": ["transfer.completed", "transfer.failed", "approval.requested"],
    "description": "Production payments worker"
  }'
Response:
{
  "id": "wh_...",
  "url": "https://hooks.example.com/sly",
  "events": ["transfer.completed", "transfer.failed", "approval.requested"],
  "secret": "whsec_...",
  "status": "active",
  "created_at": "2026-04-22T14:00:00Z"
}
Save the secret — you need it to verify signatures. It’s shown once.

Delivery shape

Every delivery is a POST with JSON body:
{
  "id": "evt_abc123",
  "type": "transfer.completed",
  "created_at": "2026-04-22T14:05:00Z",
  "data": {
    "transfer": { "id": "tx_...", "amount": "42.00", "status": "completed", ... }
  },
  "tenant_id": "ten_...",
  "environment": "live"
}
Headers include:
  • X-Sly-Signature: t=...,v1=... — HMAC signature (verify it)
  • X-Sly-Event-Id: evt_... — stable ID for idempotency
  • X-Sly-Delivery-Id: del_... — unique per delivery attempt
  • X-Sly-Webhook-Id: wh_... — which subscription

Expected response

  • 2xx — treated as success; no retry
  • Any other status or timeout → retry with exponential backoff
Respond fast. Sly’s timeout is 15 seconds; if your processing takes longer, ack immediately and process async:
app.post('/webhooks/sly', (req, res) => {
  // Verify signature
  // Enqueue job
  res.status(202).end();  // ack
});

Retries

Failed deliveries retry on this schedule (up to 72 hours):
0s → 30s → 5m → 30m → 2h → 12h → 24h → 48h (final)
Each retry includes the same X-Sly-Event-Id — use it for idempotency.

Idempotency on your side

Webhook delivery is at-least-once. Always dedupe:
if (await processedEvents.has(eventId)) return;
await processedEvents.add(eventId);
await handleEvent(event);
Keep a TTL index on processedEvents (24-48 hours is plenty).

Next steps

Event catalog

Full list of events you can subscribe to.

Signature verification

How to verify webhooks are actually from Sly.

Replay

Re-send past events during incident recovery.

Local testing

ngrok, webhook.sly.ai, tunnel setup.