Deposits
How it works
A deposit converts KES from the user's M-Pesa into USDC held in their Regini account. The flow:
- Quote (recommended): fetch a rate quote for the KES amount. The response shows the exact USDC the user will receive, the fee, and the exchange rate. The quote is locked for 10 minutes.
- Initiate: submit the deposit with the
rate_idfrom the quote. Regini sends an M-Pesa STK push to the phone number stored on the account. The API responds immediately; the deposit is now pending. - User confirms: the user approves the payment on their phone.
- Webhook: once M-Pesa confirms collection, Regini credits the USDC to the account and fires a
deposit.completedwebhook.
The M-Pesa prompt goes to the phone stored on the account. You do not supply it per-request. Your backend should listen for the webhook rather than polling for status.
Option A: Get a quote first (recommended)
Step 1: Get a rate quote
GET /accounts/{account_id}/deposit-quote?amount_kes=5000
{
"rate_id": "abc123-...",
"amount_kes": 5000.0,
"net_usdc_amount": 38.07,
"fee_usdc": 0.38,
"exchange_rate": 131.35
}
exchange_rate is the effective KES/USDC rate with the FX spread already applied, this is the rate shown to the user. The quote is valid for 10 minutes and is single-use.
Step 2: Confirm the deposit
POST /accounts/{account_id}/deposits
An Idempotency-Key header is required for safe retries:
Response:
The deposit is now pending. The user will receive an M-Pesa STK push. Once they confirm, Regini credits their account and fires a deposit.completed webhook.
Option B: Auto-confirm at live rate
Skip the quote step and execute immediately at the live rate.
POST /accounts/{account_id}/deposits
Request fields
| Field | Required | Description |
|---|---|---|
amount_kes |
Yes | KES amount to deposit |
rate_id |
Conditional | Rate quote from GET .../deposit-quote. Required when auto_confirm_rate is false. |
auto_confirm_rate |
No | Default false. When true, executes at the live rate without a prior quote. |
reference |
No | Your own reference string (max 255 chars). Returned in the webhook and transaction history. |
Limits
| Limit | Value |
|---|---|
| Minimum per transaction | KES 100 |
| Maximum per transaction | KES 250,000 |
| Daily (rolling 24 hours) | KES 500,000 per account |
| Weekly (rolling 7 days) | KES 2,000,000 per account |
Daily and weekly windows are rolling (not calendar-reset). Failed transactions do not count against the limits. Breaching a limit returns VELOCITY_LIMIT_EXCEEDED.