Skip to main content

Collect a payment (payin)

A payin debits a customer's mobile money account and credits your MoyaPay balance.

POST /payin

Requires a Bearer token.

Request body​

FieldTypeRequiredDescription
refercence_clstringyesYour merchant reference. Must match the account of the token
business_codestringyesBusiness code provided by MoyaPay. Must belong to your account
country_codestringyesCountry of the transaction: CI, SN, BF, CM, BN, RDC, CB, GMB
payment_methodstringyesPayment method code, see Payment methods
merchant_transaction_idstringyesYour transaction identifier, unique
amountnumberyesAmount, as a JSON number (not a string). See Limits
currencystringyesCurrency of the transaction's country, for example XOF. Choose it from the Currencies by country table
telephonestringyesCustomer phone number, as a string. See Limits
successUrlstringyesRedirect URL after a successful payment (redirect-based methods, such as Wave)
failedUrlstringyesRedirect URL after a failed payment
notifyUrlstringyesYour notification URL. See the note below
otp_codestringdepends on the methodRequired for OM_CI (Orange Money Côte d'Ivoire): the one-time code generated by the customer
About notifyUrl

The field is required, but callbacks are currently sent to the callback URL registered on your merchant account by MoyaPay (one URL for payins, another for payouts), not to the value sent in notifyUrl.

Example​

curl -X POST https://services.moya-pay.com/service/api/v1/payin \
-H "Authorization: Bearer $TOKEN" \
-H "Content-Type: application/json" \
-d '{
"refercence_cl": "CL-123456",
"business_code": "MYP-000000-ABCDEF",
"country_code": "CI",
"payment_method": "WAVE_CI",
"merchant_transaction_id": "ORDER-2026-000123",
"amount": 1000,
"currency": "XOF",
"telephone": "0505000000",
"successUrl": "https://shop.example.com/payment/success",
"failedUrl": "https://shop.example.com/payment/failed",
"notifyUrl": "https://shop.example.com/api/moyapay/notify"
}'

Response​

{
"status": 201,
"success": true,
"code": 200,
"message": "TRANSACTION IS INITIATED SUSSESSFULLY",
"data": {
"status": "PENDING",
"transaction_id": "ORDER-2026-000123",
"payment_url": "https://pay.wave.com/c/..."
}
}
FieldDescription
successtrue if the request is accepted. This is the field to test
data.statusInitial status of the transaction, usually PENDING
data.transaction_idYour merchant_transaction_id, keep it to follow the transaction
data.payment_urlDepends on the payment method. URL to redirect the customer to so they can approve the payment (Wave in particular)
data.deepLinks, data.validForDepends on the payment method. Link that opens the operator's app, and its validity period
data.msgDepends on the payment method. Instruction to show to the customer
Good to know

The top-level status is 201 while the HTTP status is 200: do not rely on that value. The text of message can also vary by operator: do not parse it in your code. Test success, then read data.status.

After the response​

  1. Depending on the payment method, redirect the customer to data.payment_url or show them the instruction (data.msg) so they approve on their phone.
  2. Wait for the callback, or query the transaction status.

Validation rules​

  • merchant_transaction_id must be new. An identifier that was already used returns a 400 error. Uniqueness is enforced across the whole platform: choose distinctive identifiers.
  • An identical transaction (same amount, same number, same type) still in progress for less than a minute is rejected with An identical transaction is already in progress. Please wait. Wait for the first one to finish, or change the amount.
  • The payment method must be enabled on your account, otherwise the response is Marchand not have provider.

Possible errors are listed in Errors.

On a 500 error

If initiation fails at the operator (Impossible to make the transaction, HTTP 500), the transaction is still recorded. Do not send the same merchant_transaction_id again: check its status first, then create a new transaction with a new identifier if needed.