KYC Verification
Verify user phone numbers via OTP before they can use the on/off-ramp. Required once per phone number per merchant.
Before a user can create ramp orders, their phone number must be verified via OTP (One-Time Password). This is a lightweight KYC step that ensures the Mobile Money account belongs to the user.
KYC verification is required once per phone number per merchant. After verification, the user can create unlimited orders (subject to limits) without re-verifying.
How it works
- Initiate — Your app sends the user's details. An OTP is sent to their phone.
- Verify — The user enters the OTP code. You submit it to confirm verification.
- Done — The phone is marked as verified. The user can now create ramp orders.
Step 1: Initiate KYC
curl -X POST https://api.your-domain.com/api/v1/ramp/kyc/initiate \
-H "Authorization: Bearer $SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"first_name": "Kofi",
"last_name": "Mensah",
"phone": "0241234567",
"provider_name": "MTN"
}'Request body
| Field | Type | Required | Description |
|---|---|---|---|
first_name | string | Yes | User's first name |
last_name | string | Yes | User's last name |
phone | string | Yes | User's phone number (local format, e.g. 0241234567) |
provider_name | string | Yes | Network provider: MTN, VODAFONE, TELECEL, or AIRTELTIGO |
Response
{
"success": true,
"data": {
"kyc_id": "1875fe99-4d75-4883-974e-418cb4e221f7",
"status": "otp_sent"
}
}An SMS with a 6-digit OTP is sent to the user's phone. Store the kyc_id — you need it for verification.
Already verified
If the phone number was already verified for this merchant, the API returns immediately without sending a new OTP:
{
"success": true,
"data": {
"kyc_id": "1875fe99-4d75-4883-974e-418cb4e221f7",
"status": "already_verified"
}
}Step 2: Verify OTP
Collect the OTP code from the user and submit it:
curl -X POST https://api.your-domain.com/api/v1/ramp/kyc/verify \
-H "Authorization: Bearer $SECRET_KEY" \
-H "Content-Type: application/json" \
-d '{
"kyc_id": "1875fe99-4d75-4883-974e-418cb4e221f7",
"otp_code": "482910"
}'Request body
| Field | Type | Required | Description |
|---|---|---|---|
kyc_id | string | Yes | The KYC ID returned from the initiate step |
otp_code | string | Yes | The 6-digit OTP code the user received via SMS |
Success response
{
"success": true,
"data": {
"kyc_id": "1875fe99-4d75-4883-974e-418cb4e221f7",
"phone_verified": true,
"account_name": "Kofi Mensah"
}
}Using the verified phone in orders
After verification, use the same phone number in your ramp order requests. The API will match it against the verified KYC record:
{
"type": "onramp",
"fiat_amount": 100,
"destination_wallet": "GBXYZ...",
"payment_method": "mobile_money",
"user": {
"first_name": "Kofi",
"last_name": "Mensah",
"phone": "0241234567",
"network": "MTN"
}
}If the phone hasn't been verified, the order will fail with KYC_REQUIRED.
Error codes
| Error | Meaning |
|---|---|
OTP_FAILED | Failed to send OTP — check phone number and network |
NOT_FOUND | KYC record not found for the given kyc_id |
OTP_INVALID | The OTP code is incorrect or expired |
Best practices
- Check the initiate response for
"status": "already_verified"to skip the OTP step for returning users - OTP codes expire after a few minutes — prompt the user to enter it promptly
- If the OTP fails, call
/kyc/initiateagain to send a new code - Store the verification status in your app so you only call KYC for new users
- The
provider_namemust match the user's actual MoMo network for the OTP to be delivered