Transfer between the caller's accounts
Transfer money between two of the caller's own accounts. The current version supports one pair: a current account pays a lending account. Requires an authenticated, active user. The custodian sends the caller an OTP, and the transaction waits in PENDING_OTP_CONFIRMATION until the caller confirms it with POST /v1/transactions/{id}/confirm. Both accounts record the transfer, with the counterparty account, in their transaction details. A repeated request with the same Idempotency-Key header replays the first response instead of creating a second transfer, and reusing the key with a different request body returns 409. Returns 404 when from_account_id or to_account_id does not belong to the caller, and 400 when the accounts are not a current-to-lending pair, use different currencies, or the amount exceeds the destination's outstanding balance.
Authorization
oauth2 Create a client with POST /v1/oauth/clients, then exchange its credentials for an access token. AUTHORIZATION_CODE clients act on behalf of a signed-in user and always use PKCE; CLIENT_CREDENTIALS clients act as themselves. A client may only be granted scopes its creator already holds — read the grantable list from GET /v1/oauth/clients/scopes.
In: header
Header Parameters
Unique key that de-duplicates retries of this request: the first call executes and its response is stored, identical retries replay it, and reusing a key with a different request body is rejected with 409 Conflict.
length <= 255Request Body
application/json
Request to transfer money between two of the caller's own accounts. The current version supports one pair: from a current account to a lending account.
Response Body
application/json
application/json
application/json
application/json
application/json
application/json
application/json
application/json
curl -X POST "https://example.com/v1/transactions/transfers" \ -H "Idempotency-Key: string" \ -H "Content-Type: application/json" \ -d '{ "from_account_id": "550e8400-e29b-41d4-a716-446655440000", "to_account_id": "3fa85f64-5717-4562-b3fc-2c963f66afa6", "amount": { "value": 50000, "currency": "KES" } }'{ "id": "01a11715-7b0d-7e3f-9c2a-4d5e6f708192", "resource_id": "trx_01m4bhayrdfrzsrajdbsqq10cj", "mpesa_transaction_id": "ABCDE12345", "amount": { "value": 100000, "currency": "KES" }, "fee_amount": { "value": 5000, "currency": "KES" }, "status": "COMPLETED", "failure_reason": null, "transacted_at": "2026-01-20T10:30:00Z", "confirmed_at": "2026-01-20T10:30:05Z", "posted_at": "2026-01-20T10:30:10Z", "failed_at": null, "details": { "type": "BUY_GOODS", "till_number": "12345" }}{ "code": "BAD_REQUEST", "description": "Bad Request"}{ "code": "UNAUTHORISED", "description": "Unauthorised"}{ "code": "FORBIDDEN", "description": "Forbidden"}{ "id": "01a11715-7b0d-7e3f-9c2a-4d5e6f708192", "resource_id": "trx_01m4bhayrdfrzsrajdbsqq10cj", "mpesa_transaction_id": "ABCDE12345", "amount": { "value": 100000, "currency": "KES" }, "fee_amount": { "value": 5000, "currency": "KES" }, "status": "COMPLETED", "failure_reason": null, "transacted_at": "2026-01-20T10:30:00Z", "confirmed_at": "2026-01-20T10:30:05Z", "posted_at": "2026-01-20T10:30:10Z", "failed_at": null, "details": { "type": "BUY_GOODS", "till_number": "12345" }}{ "id": "01a11715-7b0d-7e3f-9c2a-4d5e6f708192", "resource_id": "trx_01m4bhayrdfrzsrajdbsqq10cj", "mpesa_transaction_id": "ABCDE12345", "amount": { "value": 100000, "currency": "KES" }, "fee_amount": { "value": 5000, "currency": "KES" }, "status": "COMPLETED", "failure_reason": null, "transacted_at": "2026-01-20T10:30:00Z", "confirmed_at": "2026-01-20T10:30:05Z", "posted_at": "2026-01-20T10:30:10Z", "failed_at": null, "details": { "type": "BUY_GOODS", "till_number": "12345" }}{ "code": "RATE_LIMIT_EXCEEDED", "description": "Too Many Requests"}{ "code": "INTERNAL_ERROR", "description": "Internal Server Error"}Preview a transaction POST
Price a transaction before creating it. Set `type` to `SEND_MONEY`, `BUY_GOODS`, `PAY_BILL`, `POCHI`, or `PAYEE` to match the intended create operation. Requires an authenticated, active user. Every loan or credit account returns `loan_options`. The top-level `loan` field is deprecated in its favor. For `FLEX_CREDIT`, send `tenure` to price that option alone, or omit it to price every available tenure. `fee`, `total`, and `loan` are then absent, so read `loan_options` instead. Omit `tenure` for other account types. Returns 404 when `account_id`, or a `PAYEE` request's `payee_account_id`, does not belong to the caller. A `POCHI` preview, or a `PAYEE` preview of a `POCHI` payee account, refuses `POCHI_NOT_SUPPORTED_FOR_ACCOUNT`, `POCHI_NOT_AVAILABLE`, and `POCHI_AMOUNT_OUT_OF_RANGE`.
List payees GET
Get a keyset-paginated page of the caller's saved payees. Payees come favourites first, then newest first, and each payee's accounts come most-used first. Requires an authenticated, active user. Filter the page to one account `type` (`SEND_MONEY`, `POCHI`, `PAY_BILL`, `BUY_GOODS`, or `BANK_ACCOUNT`) or to `favorite` payees only. Page through the results with the `after` or `before` cursor.