Skip to main content
POST
Initiate a payment

Overview

POST /payment/collect initiates a pay-in: it charges a mobile-money account and credits the proceeds to your company’s pay-in wallet for the matching country/currency. The call returns immediately with status: PENDING; the final outcome (SUCCESS or FAILED) reaches you asynchronously via webhook (or via notify_url if you supply one). For some operators, the end user must approve the charge with an OTP or USSD step — see the country/operator matrix in Payment guidelines.

When to use it

  • You need to charge an end user’s mobile-money account to settle a bill, top up a balance, or fund a service.
For the reverse direction (sending money out to a mobile-money account), use POST /payment/payout.

Prerequisites

  • Your company has a wallet for the requested (country, currency) pair. If not, create it first via POST /wallets.
  • The combination of country, currency, and operator is supported — see Payment guidelines.

Request

Headers

Body

Orange Money workflow (Burkina Faso & Senegal)

Orange Money in Burkina Faso and Senegal requires an OTP. The operator does not push a confirmation prompt to the payer — instead the payer must generate the one-time code themselves and give it to you, then you submit it with the collection:
  1. The payer dials the Orange USSD code on their phone to generate the payment OTP:
    • Burkina Faso (country: "BF"): *144*4*6*<amount># — where <amount> is the collection amount.
    • Senegal (country: "SN"): #144*391#
  2. The payer gives you the generated OTP.
  3. You call POST /payment/collect with operator: "orange", the matching country, currency: "XOF", and the OTP in otp_code.
The OTP is short-lived (a few minutes) and single-use. If it has expired the collection fails — the payer must generate a fresh one and you retry with a new external_id.
Other operators also require an OTP (e.g. Wallet LigdiCash in Burkina Faso). Whenever the operator requires one, send it in otp_code. See the Payment guidelines for the full country/operator OTP matrix.

Idempotency

Always supply your own external_id. Cartevo rejects duplicates with 400 (after the first call), so storing the value before you send the request and reusing it on retry is safe. If you let Cartevo auto-generate one, you lose this protection.

Response

200 — Collection initiated

Wave (Côte d’Ivoire, Senegal, …) requires a payment link. Wave does not push a USSD/OTP prompt; instead AfribaPay returns a provider_link in the response and the payer must open it to confirm:
  1. Call POST /payment/collect with operator: "wave".
  2. The response contains a non-null provider_link (e.g. https://pay.wave.com/c/cos-...).
  3. Redirect the payer to that URL (or open it). They confirm the payment on Wave’s page.
  4. The transaction stays PENDING until they confirm; the final SUCCESS/FAILED arrives via webhook.
The Wave link is short-lived. If the payer doesn’t confirm in time the collection fails — retry with a new external_id to get a fresh link.

Lifecycle

  • PENDING — Cartevo accepted the request; the operator has been notified.
  • PROCESSING — The operator is awaiting user action (OTP / USSD) or processing internally.
  • SUCCESS — Funds have been credited to your pay-in wallet. The payment.collect webhook fires.
  • FAILED — End user rejected, insufficient funds at the operator, OTP timeout, etc. See error_message in the status endpoint.
PROCESSING can last up to 15 minutes for OTP-required operators. Beyond that, treat as failed and reconcile via the status endpoint.

Error responses

Webhooks fired

  • payment.collect — fires when the collection is initiated, then again on status changes (SUCCESS / FAILED).
  • If you supplied notify_url, it receives a copy of each status change.

Code examples

cURL
Node.js (axios)

Authorizations

Authorization
string
header
required

Bearer authentication header of the form Bearer <token>, where <token> is your auth token.

Body

application/json
operator
enum<string>
required
Available options:
mtn,
orange,
moov,
airtel,
mpesa,
afrimoney,
vodacom,
wave,
wligdicash,
expresso,
free,
tmoney,
celtiis,
coris
Example:

"mtn"

country
string
required
Pattern: ^[A-Z]{2}$
Example:

"CM"

phone_number
string
required
Example:

"237670000000"

amount
number
required
Required range: x >= 1
Example:

1000

currency
string
required
Example:

"XAF"

notify_url
string
Example:

"https://example.com/webhook/payment"

external_id
string

Idempotency key (up to 255 chars). Duplicate values are rejected with 400 after the first call. Auto-generated if omitted.

reference_id
string

Free-form reference shown in the dashboard (up to 255 chars).

lang
string

Two-letter language code for operator-side prompts (e.g. en, fr).

purpose
string

Free-form description of the payment's purpose.

Response

Collection initiated successfully

success
boolean
Example:

true

message
string
Example:

"Collection initiated successfully"

data
object