Kenya
M-Pesa and Airtel mobile money payments in KES
Before you start
Authorization
How to sign your requests with the API token.
Create payment
The base order request that this page extends.
This payment method is not enabled for all merchants. Check availability with your manager.
Overview
| Currency | Country code | Payment method |
|---|---|---|
KES | KE | M-Pesa, Airtel (mobile money) |
Two scenarios are available. Which scenario and which operator are enabled for your account is defined by your terminal settings.
Not sure which option you have? Ask your manager.
What is different from a regular order
The order is created through the standard POST /v1/orders endpoint. The base fields (amount, currency, successUrl, failUrl, callbackUrl, etc.) are the same as for a regular order; on top of them you pass the customer object with payer details.
| Field | Type | Description |
|---|---|---|
customer | object | Payer details. The required set is listed below |
The payer is redirected to paymentLink and confirms the payment in M-Pesa.
The externalUserId field is required for this payment method.
Customer fields
| Field | Type | Required | Description |
|---|---|---|---|
country | string | ✅ Yes | Country code, always KE |
phone | string | ⚠️ Depends on the method | Payer phone number, format 254712345678 |
email | string | ✅ Yes | Payer email |
firstName | string | ✅ Yes | First name |
lastName | string | ✅ Yes | Last name |
Request example
{
"purpose": "Payment for order #1234",
"amount": "100",
"currency": "KES",
"externalId": "external_id",
"externalUserId": "external_user_id",
"successUrl": "https://example.com/success",
"failUrl": "https://example.com/fail",
"callbackUrl": "https://example.com/webhooks/payments",
"isFeeOnUser": false,
"customer": {
"firstName": "John",
"lastName": "Doe",
"country": "KE",
"email": "john.doe@example.com"
}
}Operators: M-Pesa, Airtel.
Send the payer to paymentLink: the payment request goes to the operator when the link is opened, and the payer confirms it on their phone (push notification or USSD prompt). The page waits for the result and shows it; the final status also comes to your callbackUrl.
Customer fields
| Field | Type | Required | Description |
|---|---|---|---|
phone | string | ✅ Yes | Payer phone number, digits only with the country code: 254712345678 |
firstName | string | ⚠️ Depends on the operator | First name |
lastName | string | ⚠️ Depends on the operator | Last name |
email | string | ⚠️ Depends on the operator | Payer email |
country | string | ❌ No | Country code KE. Optional: the country is defined by the method |
The required set depends on the operator enabled on your terminal. If a field it needs is missing or the phone does not match the country format, the order is rejected with 400 listing the fields. Send firstName, lastName, email and phone whenever you have them.
Request example
{
"purpose": "Payment for order #1234",
"amount": "1000",
"currency": "KES",
"externalId": "external_id",
"externalUserId": "external_user_id",
"successUrl": "https://example.com/success",
"failUrl": "https://example.com/fail",
"callbackUrl": "https://example.com/webhooks/payments",
"isFeeOnUser": false,
"customer": {
"firstName": "John",
"lastName": "Doe",
"phone": "254712345678",
"email": "john.doe@example.com"
}
}Send whole amounts in KES: some methods do not accept fractional amounts.
Response
The response is a standard order object. The order is created with the CREATED status; redirect the payer to paymentLink to complete the payment.
Order object fields
Next steps
Order status and webhooks
Get notified when the payment is completed.
Payments by country
Other countries and payment methods.
H2H and the payment form
Ask your manager to enable H2H for the required method. The create-order request stays the same unless an extra field is listed below. Open the returned paymentLink: the platform payment form displays the QR code, bank details, or wallet action and waits for the final result. Existing payment-page integrations remain available.
H2H supports M-Pesa, Airtel Money and T-Kash. Send customer.phone: 12 digits starting with 2541 or 2547, for example 254712345678. Local numbers starting with 01 or 07 are normalized automatically. For this route, no other customer fields are required; other routes on this page may have different requirements.
{
"customer": {
"phone": "254712345678"
}
}The request is sent to the wallet when paymentLink is opened. The payer confirms on their phone, and the platform form waits for the result. This flow does not issue a QR code or receiving bank account. Do not mark the order paid until its final status or callback confirms it.