Pay-ins API
Last updated: 2026-07-17
Pay-in operations use a secret key (sk_*). Monetary amounts are strings in
minor units.
Initialize a hosted pay-in
POST /merchant/api/v1/payins/initialize
Auth: Secret key
| Body field | Type | Presence | Meaning |
|---|---|---|---|
amount | string (int64) | Required | Positive amount in minor units |
currencyCode | string | Required | ISO 4217 currency |
countryCode | string | Conditional | Selected payment-market country; required for mobile money and whenever the selected currency/method maps to more than one enabled country |
paymentSubMethod | string | Optional | Supported only for bank transfer; current value is moniepoint |
paymentMethod | enum | Required | Selected PAYMENT_METHOD_* value |
merchantReference | string | Required | Merchant-side payment reference |
redirectUrl | string | Required | Customer return URL |
trafficVertical | enum | Optional | Preferred traffic category |
customerSegment | enum | Optional | Customer segment; defaults when omitted |
mobileMoneyOperator | string | Conditional | Public operator code for operator-required standard mobile money; required transfer rail code for mobile money transfer |
{
"amount": "10000",
"currencyCode": "NGN",
"countryCode": "NG",
"paymentMethod": "PAYMENT_METHOD_BANK_ACCOUNT",
"merchantReference": "MR-1001",
"redirectUrl": "https://merchant.example/return",
"trafficVertical": "TRAFFIC_VERTICAL_OTHER"
}
The response contains paymentOrder and expiresAt. The hosted payment expires
30 minutes after creation; treat the returned UTC expiresAt value as the exact
deadline for that order. Redirect the customer only when
paymentOrder.paymentUrl is returned, and reconcile the payment after the
customer returns.
Create a direct pay-in
POST /merchant/api/v1/payins/create
Auth: Secret key
The core fields are the same as hosted initialization, except that direct
requests put method-specific input in exactly one matching detail block. Use
paymentSubMethod only with bank transfer; the current supported value is
moniepoint.
| Detail block | Used with | Fields |
|---|---|---|
bankAccountDetails | PAYMENT_METHOD_BANK_ACCOUNT | name and bankCode required; email optional |
bankTransferDetails | PAYMENT_METHOD_BANK_TRANSFER | email optional |
mobileMoneyDetails | PAYMENT_METHOD_MOBILE_MONEY | mobileNumber required; operator and voucherPin conditional; email optional |
mobileMoneyTransferDetails | PAYMENT_METHOD_MOBILE_MONEY_TRANSFER | operator and mobileNumber required |
cardDetails | PAYMENT_METHOD_CARD | Schema-visible only; card creation is not currently supported |
testDetails | PAYMENT_METHOD_TEST | Non-production controls described in Test method controls |
Example direct mobile money request:
{
"amount": "8500",
"currencyCode": "KES",
"countryCode": "KE",
"paymentMethod": "PAYMENT_METHOD_MOBILE_MONEY",
"merchantReference": "MM-2001",
"redirectUrl": "https://merchant.example/return",
"mobileMoneyDetails": {
"mobileNumber": "<customer_msisdn>",
"operator": "<operator_from_discovery>"
}
}
Method-specific response details can include:
bankAccountDetails.redirectUrlfor an authorization redirect;- bank transfer account instructions and
expiresAt; - mobile money instructions,
displayMessage, andisOtpAuthRequired. - mobile money transfer
instructions,expiresAt,displayMessage, andproviderReference.
See Mobile money transfer objects for its direct request, response, and instruction fields.
Authorize pay-in OTP
POST /merchant/api/v1/payins/authorize-otp
Auth: Secret key
Call this operation only when the create response sets
mobileMoneyDetails.isOtpAuthRequired to true.
| Body field | Type | Presence |
|---|---|---|
paymentOrderId | string (UUID) | Required |
token | string | Required |
The response contains:
isAuthorized— whether OTP authorization was accepted;isStkPromptRequired— whether the flow continues with an STK prompt;displayMessage— customer-facing next-step text.
Outcomes
Pay-in operations can return INVALID_ARGUMENT for missing, malformed, or
unavailable request values. A route that is temporarily unavailable can return
the public method_unavailable reason. OTP authorization can also return
NOT_FOUND for an unknown payment order. Handle all non-success responses using
Errors.
Related guide: Pay-ins.