Transfers & FX Conversion
These endpoints are authenticated with your API Key (X-API-Key header).
Base URL: https://rach-caas-api-dx75yvdhaq-nw.a.run.app
Get FX Conversion Quote
Returns a locked exchange rate for converting any local fiat currency to USDC. The returned quote_id must be passed to POST /v1/transfers/send for fiat-denominated transfers.
Quotes expire in 60 seconds — check expires_at before use.
For direct crypto-to-crypto transfers without FX conversion, use the
DIRECT_CRYPTO:{TOKEN}:{AMOUNT}format as thequote_idinstead (e.g.DIRECT_CRYPTO:USDC:10.50).
POST /v1/fx/quote
Request
POST /v1/fx/quote
X-API-Key: rach_sk_live_xxxxxxxxxxxxxxxx
Content-Type: application/json
{
"local_currency": "XOF",
"fiat_amount": 20000,
"target_token": "USDC"
}| Field | Type | Required | Description |
|---|---|---|---|
local_currency | string | ✅ | ISO 4217 currency code (e.g. "XOF", "NGN", "KES", "GHS", "EUR", "USD") |
fiat_amount | number | ✅ | Amount in local currency (e.g. 20000) |
target_token | string | — | Defaults to "USDC" |
Response 200 OK
{
"quote_id": "fx_b3d8a1c2-4f5e-6789-abcd-ef0123456789",
"currency_pair": "XOF_USDC",
"fiat_amount": "20000.00",
"rate": "560.77",
"expected_out": "35.67",
"target_token": "USDC",
"expires_at": "2026-06-25T12:01:05Z"
}| Field | Description |
|---|---|
quote_id | Locked rate token — pass this to /v1/transfers/send |
currency_pair | Trading pair (e.g. XOF_USDC, NGN_USDC, KES_USDC) |
rate | Local currency units per USDC at lock time |
expected_out | USDC amount the recipient will receive |
expires_at | ISO 8601 timestamp — quote invalid after this |
Error Codes
| Status | Meaning |
|---|---|
400 | Invalid currency or missing fields |
401 | Invalid or missing API key |
500 | FX engine error or unsupported trading pair |
Send Instant On-Chain Transfer
Moves USDC between two customer SCWs on Polygon PoS via an ERC-4337 UserOperation. Settlement is on-chain and final within seconds — no banks, no correspondents, no cut-off times.
Both sender and recipient must be provisioned users under your tenant.
AML daily/monthly limits apply per sender. Exceeding them returns 429.
POST /v1/transfers/send
Request — With FX Quote
POST /v1/transfers/send
X-API-Key: rach_sk_live_xxxxxxxxxxxxxxxx
Content-Type: application/json
{
"sender_phone": "+2250700000001",
"recipient_phone": "+2250700000002",
"quote_id": "fx_b3d8a1c2-4f5e-6789-abcd-ef0123456789",
"local_fiat_amount": "5500.00",
"target_token": "USDC",
"idempotency_key": "txn_ref_abc123"
}Request — Direct Crypto (No FX)
POST /v1/transfers/send
X-API-Key: rach_sk_live_xxxxxxxxxxxxxxxx
Content-Type: application/json
{
"sender_phone": "+2250700000001",
"recipient_phone": "+2250700000002",
"quote_id": "DIRECT_CRYPTO:USDC:10.50",
"local_fiat_amount": "10.50",
"target_token": "USDC",
"idempotency_key": "txn_ref_direct_001"
}| Field | Type | Required | Description |
|---|---|---|---|
sender_phone | string | ✅ | Sender's E.164 phone number |
recipient_phone | string | ✅ | Recipient's E.164 phone number |
quote_id | string | ✅ | From POST /v1/fx/quote, or DIRECT_CRYPTO:USDC:{amount} |
local_fiat_amount | string | ✅ | Original fiat amount (for audit/ledger) |
target_token | string | ✅ | "USDC" or "USDT" |
idempotency_key | string | ✅ | Your unique reference — prevents duplicate UserOps |
Response 202 Accepted
{
"transfer_id": "txn_abc123xyz",
"status": "QUEUED",
"message": "Transfer queued for on-chain submission",
"created_at": "2026-06-25T12:05:00Z"
}Transfer lifecycle: QUEUED → SUBMITTED → SETTLED
Monitor progress via GET /v1/dashboard/transfers/{id}
Error Codes
| Status | Meaning |
|---|---|
400 | Invalid payload or expired FX quote |
401 | Invalid or missing API key |
404 | Sender or recipient wallet not provisioned |
409 | Duplicate idempotency_key |
410 | FX quote expired (>60 seconds since quote was issued) |
429 | AML block: daily or monthly sending limit exceeded |
Transfer Flow
┌─────────────────────────────────────────────────┐
│ 1. POST /v1/fx/quote │
│ → Receive locked quote_id (60s TTL) │
└────────────────────────┬────────────────────────┘
│
▼
┌─────────────────────────────────────────────────┐
│ 2. POST /v1/transfers/send (with quote_id) │
│ → Transfer queued (QUEUED) │
│ → ERC-4337 UserOp submitted (SUBMITTED) │
│ → On-chain settlement (SETTLED) │
└─────────────────────────────────────────────────┘For very time-sensitive flows, you can pre-fetch a quote speculatively and pass it immediately when the user confirms. Quotes are valid for 60 seconds from issuance.
AML Limits
Rach CaaS enforces per-sender AML velocity controls. If a sender exceeds their daily or monthly USDC transfer limit, the transfer returns HTTP 429. Contact support@rach.finance to adjust limits for your use case.
