Skip to main content
This page lists the events Sly emits today + their payload shapes. Event types are extracted from 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:
{
  "id": "evt_<uuid>",
  "type": "<event.type>",
  "timestamp": "2026-04-23T15:30:00Z",
  "data": { ... }
}
Headers:
  • X-Sly-Signature: t=<unix_ts>,v1=<hmac_sha256_hex>verify this
  • X-Sly-Event-Id: evt_<uuid> — stable ID; dedupe in your handler
  • X-Sly-Delivery-Id: del_<uuid> — unique per delivery attempt
  • X-Sly-Webhook-Id: wh_<uuid> — which subscription triggered this

Transfer events

EventFires when
transfer.createdNew transfer record created
transfer.completedTransfer settled
transfer.failedTransfer settlement failed
transfer.refundedTransfer was refunded
data:
{
  "transfer_id": "tx_<uuid>",
  "type": "cross_border | internal | stream_start | stream_withdraw | stream_cancel | wrap | unwrap",
  "status": "pending | processing | completed | failed | cancelled",
  "amount": "42.00",
  "currency": "USDC",
  "from_account_id": "acc_<uuid>",
  "to_account_id": "acc_<uuid>",
  "protocol": "ucp | acp | ap2 | x402 | mpp | internal | cross_border",
  "completed_at": "2026-04-23T15:30:00Z"
}

Settlement events

Fired when payouts transition through Circle (stablecoin → fiat) or other rails.
EventFires when
settlement.initiatedPayout submitted to rail (status: pending)
settlement.processingPayout accepted by rail (status: confirmed)
settlement.completedPayout finalized
settlement.failedPayout rejected by rail
settlement.returnedPayout returned (ACH return, chargeback)
data:
{
  "payoutId": "payout_<external>",
  "transferId": "tx_<uuid>",
  "status": "pending | confirmed | complete | failed | returned",
  "amount": "500.00",
  "destination": { "type": "bank | wallet", "ref": "..." },
  "return": { "reason": "R01 — insufficient funds", "code": "R01" },
  "errorCode": "rejected_by_rail"
}
return and errorCode are only present for returned/failed states.

Batch events

For batch transfers and mass operations.
EventFires when
batch.createdBatch queued
batch.processingBatch processing started
batch.completedAll items processed (success or failure)
batch.failedBatch processing errored at the batch level
data:
{
  "batch_id": "bat_<uuid>",
  "status": "pending | processing | completed | failed",
  "total_count": 50,
  "success_count": 48,
  "failed_count": 2,
  "total_amount": "12500.00",
  "currency": "USDC"
}

Reconciliation events

EventFires when
reconciliation.completedReconciliation run finished
reconciliation.discrepancyDiscrepancy detected during recon
data for reconciliation.completed:
{
  "report_id": "recon_<uuid>",
  "rail": "ach | wire | usdc-base | usdc-solana | pix | spei | card-stripe",
  "period": { "from": "2026-04-22", "to": "2026-04-22" },
  "totals": {
    "matched": 1244,
    "unmatched_ledger": 3,
    "unmatched_rail": 1,
    "discrepancies": 4
  }
}

x402 events

EventFires when
x402.payment.completedx402 payment settled to endpoint owner
x402.endpoint.createdNew x402 endpoint registered
data for x402.payment.completed:
{
  "payment_id": "x402_pay_<uuid>",
  "endpoint_id": "epd_<uuid>",
  "amount": "0.05",
  "currency": "USDC",
  "payer_wallet": "0x...",
  "proof": "0x...",
  "tx_hash": "0x..."
}

AP2 events

EventFires when
ap2.mandate.createdNew mandate signed and issued
ap2.mandate.executedMandate execution recorded
ap2.mandate.revokedMandate revoked
data for ap2.mandate.executed:
{
  "mandate_id": "ap2_mnd_<uuid>",
  "execution_id": "ap2_exec_<uuid>",
  "agent_id": "agt_<uuid>",
  "merchant_id": "mer_<uuid>",
  "amount": "49.00",
  "currency": "USD",
  "remaining_daily": "451.00",
  "remaining_monthly": "4851.00"
}

ACP events

EventFires when
acp.checkout.createdNew ACP checkout session
acp.checkout.completedCheckout completed with payment
acp.checkout.expiredSession expired without completion
data:
{
  "checkout_id": "acp_chk_<uuid>",
  "merchant_id": "mer_<uuid>",
  "status": "created | pending_payment | paid | fulfilled | expired",
  "total": "49.98",
  "currency": "USD",
  "items": [ { "sku": "...", "quantity": 2, "unit_price": "24.99" } ]
}

Account events

EventFires when
account.createdNew account created
account.updatedAccount record modified
account.balance.lowAccount balance below configured threshold
data for account.balance.low:
{
  "account_id": "acc_<uuid>",
  "wallet_id": "wal_<uuid>",
  "balance": "42.10",
  "threshold": "100.00",
  "currency": "USDC"
}

System events

EventFires when
webhook.testYou triggered POST /v1/webhooks/:id/test
webhook.dlqA delivery exhausted retries and entered dead-letter queue
data for webhook.test:
{
  "message": "This is a test webhook",
  "endpoint_id": "wh_<uuid>",
  "endpoint_name": "Production payments worker"
}

Subscribing

curl -X POST https://api.getsly.ai/v1/webhooks \
  -H "Authorization: Bearer pk_live_..." \
  -d '{
    "url": "https://hooks.example.com/sly",
    "events": ["transfer.*", "settlement.completed", "ap2.mandate.executed"],
    "description": "Production payments"
  }'
  • Specific events: "transfer.completed"
  • Wildcards: "transfer.*" (all transfer events)
  • Everything: "*" (not recommended in production — high volume)

Enumerate supported events programmatically

curl https://api.getsly.ai/v1/webhooks/events \
  -H "Authorization: Bearer pk_live_..."
Returns the current event catalog in machine-readable form — useful if you’re building a dashboard where users pick events to subscribe to.

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 instead
  • dispute.* / refund.* as distinct events — currently surfaced through transfer.refunded and audit log; dedicated events planned
  • agent.* lifecycle events (tier upgrade, key rotation, etc.)
  • quote.*, mpp.*, a2a.task.*
  • funding.transaction.*, treasury.alert.*
  • card.dispute.*
If any of these are critical for your integration, check support — we can either prioritize emission or suggest a polling alternative.

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 }
See webhooks overview for the full delivery contract.