Account Provisioning
How it works
Provisioning creates a Regini USDC account for one of your users. You do this once per user. It is idempotent, so calling it twice for the same external_user_id returns the same account_id without creating a duplicate.
What happens when you call POST /accounts:
- Regini registers the user and opens a USDC account, returning an
account_idimmediately - In the background, a Turnkey sub-wallet is provisioned on-chain for the account (takes a few seconds; the account is usable for deposits and withdrawals before this completes)
- You store the
account_idon your side. This is the identifier for every subsequent API call
The user's phone, first_name, and last_name are collected at this step because they are required by M-Pesa for STK push and payout. You can update them later via PATCH /accounts/{account_id} if they change.
KYC: Regini does not perform identity verification. You run your own KYC and pass the result as kyc_status: "verified". Unverified accounts cannot initiate withdrawals.
List accounts
GET /accounts
Returns all accounts you have provisioned, sorted newest first.
Query parameters:
| Parameter | Default | Description |
|---|---|---|
limit |
20 | Results per page (max 100) |
page |
1 | Page number |
Response:
{
"total_count": 2,
"page": 1,
"limit": 20,
"accounts": [
{
"account_id": "3f8a1b2c-...",
"status": "active",
"external_user_id": "your-internal-user-id",
"yield_enabled": false,
"created_at": "2026-07-21T10:00:00Z"
}
]
}
Create an account
POST /accounts
Creates a Regini USDC account for one of your users. Returns an account_id that you store on your side and use for all subsequent API calls.
This call is idempotent on your external_user_id; calling it twice for the same user returns the same account_id.
Request:
{
"external_user_id": "your-internal-user-id",
"phone": "+254700000000",
"first_name": "Jane",
"last_name": "Doe",
"program_id": "your-program-uuid",
"kyc_status": "verified",
"yield_enabled": true
}
| Field | Required | Description |
|---|---|---|
external_user_id |
Yes | Your internal user identifier. Used for idempotency. |
phone |
Yes | E.164 format (e.g. +254700000000). Used for M-Pesa. |
first_name |
Yes | User's first name |
last_name |
Yes | User's last name |
program_id |
Yes | Your Regini program UUID (provided during onboarding) |
kyc_status |
Yes | Pass "verified" when your user has passed KYC. Unverified accounts cannot withdraw. |
yield_enabled |
No | Whether this account earns yield on its USDC balance. Defaults to your tenant's yield setting, if yield is enabled for your tenant, this is true unless you explicitly pass false. Phase 2 feature; has no effect in Phase 1. |
Response:
| Field | Description |
|---|---|
account_id |
Store this; used for all subsequent calls |
created |
true if a new account was provisioned; false if the external_user_id was already registered (idempotent return) |
Wallet provisioning
The account is immediately active for KES deposits and withdrawals. A Turnkey sub-org (on-chain wallet) is provisioned asynchronously in the background. Check wallet_provisioning_status via GET /accounts/{account_id} if you need to verify wallet readiness. In sandbox, the wallet is marked active immediately; no async step.
Get account details
GET /accounts/{account_id}
Returns account status and the stored user profile.
{
"account_id": "3f8a1b2c-...",
"status": "active",
"wallet_provisioning_status": "active",
"yield_enabled": false,
"user": {
"external_user_id": "your-internal-user-id",
"first_name": "Jane",
"last_name": "Doe",
"phone_number": "+254700000000",
"kyc_verified": true
}
}
| Field | Description |
|---|---|
status |
Account status: active, inactive, or suspended. inactive is set via POST /accounts/{id}/deactivate. suspended is set by Regini (e.g. for compliance reasons), contact support. |
wallet_provisioning_status |
pending, active, or failed; tracks on-chain wallet setup. If failed, contact Regini support, the account remains usable for M-Pesa deposits and withdrawals but on-chain operations will be unavailable. |
yield_enabled |
Whether the account participates in yield pools (Phase 2). Reflects the value set at provisioning, subject to the tenant-level yield flag. Migration to yield for existing accounts is handled by Regini, not via the partner API. |
Update an account
PATCH /accounts/{account_id}
Updates the phone number or name stored on the account. At least one field must be provided. Only the supplied fields are changed.
Request:
| Field | Required | Description |
|---|---|---|
phone |
No | New M-Pesa number in E.164 format. Used for all future STK pushes and payouts. |
first_name |
No | Updated first name |
last_name |
No | Updated last name |
Response: The updated account object (same shape as GET /accounts/{account_id}).
Warning
Updating phone affects all future M-Pesa transactions on this account. Confirm the new number is correct and belongs to the same user before calling this endpoint.
Deactivate an account
POST /accounts/{account_id}/deactivate
Sets the account status to inactive. Inactive accounts cannot initiate new deposits or withdrawals.
No request body required.
Response:
Returns the same response if the account is already inactive (idempotent).
Errors:
| Code | HTTP | When |
|---|---|---|
DEACTIVATION_BLOCKED |
409 | A withdrawal is currently in-flight; wait for it to complete |
Info
Re-activation requires Regini support. Deactivation does not affect funds, the user's USDC balance is preserved and can be viewed via GET /accounts/{account_id}/balance.