Decaf
Contents

API reference/Getting started

Pay anyone, anywhere, from code.

Payouts to bank accounts in 40 currencies, mobile money, wallets or a phone number. Batches with approvals, payment links, virtual accounts and signed webhooks. Generated from the OpenAPI spec; fees, limits and arrival times come back on every channel and every quote.

One USDC balance. Fund by bank transfer in USD, EUR or MXN, or on-chain. Pay out to bank accounts in 40 currencies, a mobile payment account, a wallet, or a phone number or email. A first payout is five calls: list channels, save a recipient with the fields that corridor needs, quote, send with an idempotency key, then poll or subscribe.

List channels

GET/channels

Every destination with status, coverage, recipient type, limits, typical arrival and your fee at your current tier.

Response 200

{
  "data": [
    {
      "id": "spei_mxn",
      "status": "live",
      "country": "MX",
      "currency": "MXN",
      "rail": "spei",
      "recipient_type": "bank_account",
      "arrival": {
        "min": "PT0M",
        "max": "PT5M"
      },
      "limits": {
        "min": "30.12",
        "max": "300000.00",
        "currency": "USDC"
      },
      "fee": {
        "percent": "0.35",
        "flat": "0.50",
        "currency": "USDC"
      }
    },
    {
      "id": "claim_link",
      "status": "live",
      "country": null,
      "currency": "USDC",
      "rail": "claim_link",
      "recipient_type": "phone",
      "arrival": {
        "min": "PT0M",
        "max": "P30D"
      },
      "limits": {
        "min": "1.00",
        "max": "50000.00",
        "currency": "USDC"
      },
      "fee": {
        "percent": "0",
        "flat": "0",
        "currency": "USDC"
      }
    }
  ]
}

Create a recipient

POST/recipients

Parameters

  • Idempotency-Keyheaderstringoptional
FieldTyperequiredNotes
typeRecipientTyperequired
countrystringoptional
currencystringoptional
namestringoptional
kindenum: individual, businessoptional
external_idstringoptional
bank_accountobjectoptionalFields from the channel requirements.
pagomovilobjectoptional
walletobjectoptional
phoneobjectoptional
emailobjectoptional
decaf_userobjectoptional

Request

{
  "type": "bank_account",
  "country": "HK",
  "currency": "HKD",
  "external_id": "vendor-4471",
  "name": "Brightway Electronics Ltd",
  "kind": "business",
  "bank_account": {
    "bank_name": "HSBC",
    "account_number": "123456789012",
    "swift": "HSBCHKHHHKH",
    "id_document_number": "12345678-000-01-23-4"
  }
}

Response 201

{
  "id": "rcp_9d1a",
  "type": "bank_account",
  "country": "HK",
  "currency": "HKD",
  "name": "Brightway Electronics Ltd",
  "kind": "business",
  "external_id": "vendor-4471",
  "status": "ready",
  "channels": [
    "chats_hkd"
  ],
  "bank_account": {
    "bank_name": "HSBC",
    "account_number": "•••• 9012",
    "swift": "HSBCHKHHHKH"
  },
  "created_at": "2026-09-16T14:59:00Z"
}

Errors: 422 recipient_not_ready

Create a quote

POST/quotes

Price one payout on one channel. Provide source_amount or destination_amount. Valid 60 seconds.

FieldTyperequiredNotes
channelstringrequired
source_amountAmountoptionalDecimal string. Up to two decimals for fiat, six for USDC.
destination_amountAmountoptionalDecimal string. Up to two decimals for fiat, six for USDC.

Request

{
  "channel": "chats_hkd",
  "source_amount": "2500.00"
}

Response 201

{
  "id": "qt_5m2n",
  "channel": "chats_hkd",
  "source_amount": "2500.00",
  "source_currency": "USDC",
  "destination_amount": "19491.72",
  "destination_currency": "HKD",
  "rate": "7.8280",
  "fees": {
    "provider": "1.25",
    "decaf": "8.75",
    "fx_spread": "3.90",
    "total": "13.90",
    "currency": "USDC"
  },
  "arrival": {
    "min": "PT1M",
    "max": "P3D"
  },
  "expires_at": "2026-09-16T15:04:05Z"
}

Errors: 400 validation_error, channel_unavailable, amount_out_of_range

Create a payout

POST/payouts

One transfer to one recipient on one channel. Pass a saved recipient_id or an inline recipient. Either source_amount or destination_amount. quote_id is optional; without it the payout is priced at execution.

Parameters

  • Idempotency-Keyheaderstringoptional
FieldTyperequiredNotes
recipient_idstringoptional
recipientInlineRecipientoptional
channelstringrequired
quote_idstringoptional
source_amountAmountoptionalDecimal string. Up to two decimals for fiat, six for USDC.
destination_amountAmountoptionalDecimal string. Up to two decimals for fiat, six for USDC.
referencestringoptional
memostringoptionalTravels with the payment where the rail supports it.
messagestringoptionalClaim links only. Shown to the recipient.

Request

{
  "recipient_id": "rcp_9d1a",
  "channel": "spei_mxn",
  "quote_id": "qt_5m2n",
  "source_amount": "1000.00",
  "reference": "INV-2026-0912",
  "memo": "Freight, week 37"
}

Response 201

{
  "id": "po_1b7e",
  "status": "submitted",
  "channel": "spei_mxn",
  "recipient_id": "rcp_9d1a",
  "source_amount": "1000.00",
  "source_currency": "USDC",
  "destination_amount": "16865.35",
  "destination_currency": "MXN",
  "rate": "16.86535",
  "fees": {
    "provider": "0.50",
    "decaf": "5.00",
    "total": "5.50",
    "currency": "USDC"
  },
  "reference": "INV-2026-0912",
  "estimated_arrival": "2026-09-16T15:20:00Z",
  "provider_reference": null,
  "attempts": 1,
  "created_at": "2026-09-16T15:01:12Z"
}

Errors: 400 validation_error, channel_unavailable, amount_out_of_range; 402 insufficient_balance; 409 idempotency_conflict; 410 quote_expired

Examples: Create a payout

curl -X POST https://sandbox.api.decaf.so/v1/payouts \
  -H "Authorization: Bearer $DECAF_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: $(uuidgen)" \
  -d '{"recipient_id":"rcp_9d1a","channel":"spei_mxn","quote_id":"qt_5m2n","source_amount":"1000.00","reference":"INV-2026-0912","memo":"Freight, week 37"}'

Get a payout

GET/payouts/{id}

Includes an attempts array with timing, status and provider error per attempt.

Parameters

  • idpathstringrequired

Reference FAQ

Questions about the reference.

Get access

Build against the sandbox this week.

Tell us the corridors you need and the recipients you pay. Sandbox keys are issued by a person.