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

Transfer types

TypePurpose
cross_borderFX’d transfer between currencies (requires a quote)
internalSame-currency transfer within Sly (near-instant)
stream_startOpens a money stream
stream_withdrawWithdraws accrued balance from a stream
stream_cancelTerminates a stream and returns unspent funds
wrapConverts native token to Sly’s internal ledger format
unwrapThe reverse
Most integrations use cross_border and internal heavily and touch the others via higher-level stream APIs.

Lifecycle

pending ──▶ processing ──▶ completed
    │             │
    │             ▼
    │          failed

cancelled
  • 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

curl -X POST https://sandbox.getsly.ai/v1/transfers \
  -H "Authorization: Bearer pk_test_..." \
  -H "Content-Type: application/json" \
  -d '{
    "type": "internal",
    "from_wallet_id": "wal_source_...",
    "to_wallet_id": "wal_dest_...",
    "amount": "42.00",
    "currency": "USDC",
    "memo": "Monthly subscription",
    "idempotency_key": "tx_2026-04-22_001"
  }'
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
curl https://api.getsly.ai/v1/transfers/tx_... \
  -H "Authorization: Bearer pk_live_..."
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:
# 1. Quote
QUOTE=$(curl -X POST https://api.getsly.ai/v1/quotes \
  -H "Authorization: Bearer pk_live_..." \
  -d '{
    "from_currency": "USD",
    "to_currency": "EUR",
    "amount": "1000.00"
  }')

# 2. Execute
curl -X POST https://api.getsly.ai/v1/transfers \
  -H "Authorization: Bearer pk_live_..." \
  -d '{
    "type": "cross_border",
    "from_wallet_id": "wal_...",
    "to_wallet_id": "wal_...",
    "quote_id": "qt_...",
    "idempotency_key": "..."
  }'
Quotes expire (default TTL: 30 seconds). Expired → re-quote.

Batch transfers

For payroll, mass disbursements, or marketplace payouts:
curl -X POST https://api.getsly.ai/v1/transfers/batch \
  -H "Authorization: Bearer pk_live_..." \
  -d '{
    "transfers": [
      { "to_account_id": "acc_a", "amount": "100", "currency": "USDC" },
      { "to_account_id": "acc_b", "amount": "250", "currency": "USDC" }
    ],
    "idempotency_key": "payroll_2026_04"
  }'
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:
curl -X POST https://api.getsly.ai/v1/scheduled-transfers \
  -d '{ ..., "scheduled_at": "2026-05-01T09:00:00Z" }'
A background worker executes at the scheduled time (30s polling in sandbox, 60s in production).