B2B — Wallet Provisioning & User Management
These endpoints are authenticated with your API Key (X-API-Key header).
Base URL: https://rach-caas-api-dx75yvdhaq-nw.a.run.app
Provision User SCW Address
Creates a non-custodial ERC-4337 Smart Contract Wallet (SCW) for a customer. The wallet address is derived offline using a deterministic cryptographic salt tied to the customer's phone number — no gas, no blockchain transaction is required at this stage.
Safe to call multiple times: returns ALREADY_EXISTS with the same wallet address if the customer already has a wallet.
POST /v1/users/provision
Request
POST /v1/users/provision
X-API-Key: rach_sk_live_xxxxxxxxxxxxxxxx
Content-Type: application/json
{
"phone_number": "+2250700000001"
}| Field | Type | Required | Description |
|---|---|---|---|
phone_number | string | ✅ | Customer's phone number in E.164 format (e.g. +2250700000001) |
Response 200 OK
{
"wallet_address": "0xA1b2c3d4e5f6...",
"blind_index": "3f8a1c...",
"status": "CREATED",
"created_at": "2026-06-25T12:00:00Z"
}| Field | Description |
|---|---|
wallet_address | The customer's deterministic Polygon SCW address |
blind_index | Opaque privacy-preserving reference to this user (used in dashboard APIs) |
status | CREATED or ALREADY_EXISTS |
Error Codes
| Status | Meaning |
|---|---|
400 | Invalid phone number format (must be E.164) |
401 | Invalid or missing API key |
500 | Factory address computation failed |
Get Customer USDC Balance
Returns the live on-chain USDC balance for a customer's SCW, read directly from Polygon via eth_call. No caching — always reflects settled state.
GET /v1/users/balance?phone_number={phone}
Request
GET /v1/users/balance?phone_number=%2B2250700000001
X-API-Key: rach_sk_live_xxxxxxxxxxxxxxxxURL-encode the
+sign as%2Bin query strings.
| Parameter | Type | Required | Description |
|---|---|---|---|
phone_number | string (query) | ✅ | Customer E.164 phone (URL-encoded) |
Response 200 OK
{
"wallet_address": "0xA1b2c3d4e5f6...",
"balance_usdc": "12.500000"
}Error Codes
| Status | Meaning |
|---|---|
400 | Missing phone_number parameter |
401 | Invalid or missing API key |
404 | Wallet not provisioned for this phone number |
Fund Customer SCW (On-Ramp)
Credits a customer's SCW with USDC on Polygon PoS by triggering an ERC-20 transfer from the Rach treasury EOA. Debits your internal USDC balance atomically. Returns 402 if your treasury balance is insufficient.
Idempotent: supply a stable deposit_id to safely retry without double-crediting.
POST /v1/users/fund
Request
POST /v1/users/fund
X-API-Key: rach_sk_live_xxxxxxxxxxxxxxxx
Content-Type: application/json
{
"phone_number": "+2250700000001",
"deposit_id": "dep_001_20240601",
"local_fiat_amount": "11000.00",
"stablecoin_amount": "19.62",
"target_token": "USDC"
}| Field | Type | Required | Description |
|---|---|---|---|
phone_number | string | ✅ | Customer E.164 phone number |
deposit_id | string | ✅ | Your unique idempotency key for this deposit (e.g. dep_001_20240601) |
local_fiat_amount | string | ✅ | Original fiat amount collected (e.g. "11000.00") |
stablecoin_amount | string | ✅ | USDC amount to credit (e.g. "19.62") |
target_token | string | ✅ | "USDC" or "USDT" |
Response 202 Accepted
{
"deposit_id": "dep_001_20240601",
"status": "QUEUED",
"message": "Deposit queued for on-chain settlement",
"created_at": "2026-06-25T12:05:00Z"
}Status progresses: QUEUED → SETTLED
Error Codes
| Status | Meaning |
|---|---|
400 | Invalid payload or missing fields |
401 | Invalid or missing API key |
402 | Insufficient tenant USDC balance — top up via /v1/dashboard/treasury/topup |
404 | Customer wallet not provisioned — call /v1/users/provision first |
409 | Duplicate deposit_id — already processed |
Initiate Off-Ramp Withdrawal
Sweeps USDC from a customer's SCW back to the Rach treasury via an ERC-4337 UserOperation. Once USDC is confirmed on-chain (CRYPTO_RECEIVED), Rach disburses local fiat to the customer via the specified mobile money network.
POST /v1/users/withdraw
Request
POST /v1/users/withdraw
X-API-Key: rach_sk_live_xxxxxxxxxxxxxxxx
Content-Type: application/json
{
"phone": "+2250700000002",
"amount": "0.500000",
"token": "USDC",
"payout_mobile": "+2250700000002",
"payout_network": "orange_money",
"idempotency_key": "wdrl_ref_001"
}| Field | Type | Required | Description |
|---|---|---|---|
phone | string | ✅ | Customer E.164 phone number (SCW owner) |
amount | string | ✅ | USDC amount to withdraw (e.g. "0.500000") |
payout_mobile | string | ✅ | Mobile number for local fiat disbursement |
payout_network | string | ✅ | Mobile money network (e.g. orange_money, wave, mtn_momo) |
token | string | — | Defaults to "USDC" |
idempotency_key | string | — | Recommended for safe retries |
Response 202 Accepted
{
"withdrawal_id": "wdrl_abc123",
"status": "PENDING",
"message": "Withdrawal initiated. USDC sweep submitted on-chain."
}Withdrawal lifecycle: PENDING → SUBMITTED → CRYPTO_RECEIVED → COMPLETED
Monitor progress: GET /v1/dashboard/withdrawals/{id}
Error Codes
| Status | Meaning |
|---|---|
400 | Invalid payload or phone format |
401 | Invalid or missing API key |
404 | Customer wallet not found |
500 | Failed to create withdrawal record or enqueue task |
Update Customer Phone Number
Migrates a customer's identity to a new phone number while preserving their exact SCW address, on-chain USDC balance, and full transaction history. Use when a customer loses their SIM or changes their number.
Only the phone lookup index is updated — the wallet address is immutable.
POST /v1/users/update-phone
Request
POST /v1/users/update-phone
X-API-Key: rach_sk_live_xxxxxxxxxxxxxxxx
Content-Type: application/json
{
"old_phone_number": "+2250700000001",
"new_phone_number": "+2250700000099"
}| Field | Type | Required | Description |
|---|---|---|---|
old_phone_number | string | ✅ | Existing registered phone number |
new_phone_number | string | ✅ | New phone number to map to the same SCW |
Response 200 OK
Returns the same schema as Provision User SCW, with the existing wallet_address and updated blind_index.
Error Codes
| Status | Meaning |
|---|---|
400 | Invalid phone format (must be E.164) |
401 | Invalid or missing API key |
404 | Original phone number not found |
409 | New phone number already registered to another wallet |
