Skip to main content
A transfer is a single, discrete movement of money. Compare with streams, which are continuous flows.

Transfer types

Most integrations use cross_border and internal heavily and touch the others via higher-level stream APIs.

Lifecycle

  • pending — queued, not yet submitted to settlement
  • processing — submitted, awaiting on-chain or rail confirmation
  • completed — finalized; funds settled at destination
  • failed — settlement rejected (insufficient funds, rail error, compliance block)
  • cancelled — withdrawn before submission (only from pending)
Typical sandbox settlement time: ~2–5 seconds. Live settlement varies by rail (Base L2: ~10s; US ACH: 1–2 business days).

Create a transfer

Always send an idempotency_key. Transfers are the most dangerous thing to accidentally duplicate. Sly caches the key for 24 hours — resubmissions return the original result without re-executing.

Watch it settle

Three options: 1. Poll the transfer
2. Subscribe to webhooks — you’ll receive transfer.created, transfer.completed, transfer.failed, transfer.refunded. See webhooks. 3. Open an SSE connection — agents with sess_* tokens receive transfer_completed events pushed to their persistent channel.

Cross-border transfers

Cross-border transfers need a quote for the FX rate. Quote first, then use the quote_id on the transfer:
Quotes expire (default TTL: 30 seconds). Expired → re-quote.

Batch transfers

For payroll, mass disbursements, or marketplace payouts:
Returns a batch ID; each child transfer gets its own lifecycle. Partial failures are possible (some succeed, some fail).

Refunds and disputes

  • Refunds — full or partial reversal of a completed transfer. See /v1/refunds.
  • Disputes — chargeback-style workflow for cards. See /v1/disputes.

Scheduled transfers

Create a transfer for future execution:
A background worker executes at the scheduled time (30s polling in sandbox, 60s in production).