Initiate a payment
Payment Collection
Initiate Payment Collection
Charge a mobile-money account to credit your company’s pay-in wallet. Supports MTN, Orange, Moov, Wave, M-Pesa, and other African operators.
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.
POST /payment/payout.
Prerequisites
- Your company has a wallet for the requested
(country, currency)pair. If not, create it first viaPOST /wallets. - The combination of
country,currency, andoperatoris supported — see Payment guidelines.
Request
Headers
| Name | Required | Description |
|---|---|---|
Authorization | Yes | Bearer <access_token> |
Content-Type | Yes | application/json |
Body
| Field | Type | Required | Constraints / format |
|---|---|---|---|
operator | string | Yes | One of mtn, orange, moov, airtel, mpesa, afrimoney, vodacom, wave, wligdicash, expresso, free, tmoney, celtiis, coris. Lowercase. |
country | string | Yes | ISO 3166-1 alpha-2, uppercase (e.g. CM, CI, SN). Selects the wallet. |
phone_number | string | Yes | Country code + local number, no + (e.g. 237670000000). This format is specific to payments; other endpoints use E.164 with +. |
amount | number | Yes | Minimum 1. Unit is the major currency unit of currency. |
currency | string | Yes | ISO 4217. Must match a wallet you own. Common values: XAF, XOF, CDF, GNF, USD. |
external_id | string | No | Idempotency key. Up to 255 chars. If you supply the same value twice, the second call is rejected with 400. Auto-generated if omitted (you lose idempotency). |
notify_url | string | No | HTTPS URL to receive the final status webhook. If omitted, only the company-level webhook is fired. |
reference_id | string | No | Free-form reference shown in the dashboard. Up to 255 chars. |
lang | string | No | Two-letter language code for any operator-side prompts (e.g. en, fr). |
purpose | string | No | Free-form description of why the collection is happening (e.g. "Invoice payment"). |
Idempotency
Always supply your ownexternal_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
| Field | Type | Description |
|---|---|---|
transaction_id | string | Cartevo transaction ID (UUID). Use this for GET /payment/transactions/{id}/status. |
external_id | string | Echoes your idempotency key (or the auto-generated one). |
status | string | PENDING immediately after this call. Other values: PROCESSING, SUCCESS, FAILED. |
initiated_at | string | ISO 8601 (UTC). |
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. Thepayment.collectwebhook fires.FAILED— End user rejected, insufficient funds at the operator, OTP timeout, etc. Seeerror_messagein 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
| Status | message example | Trigger |
|---|---|---|
400 | "Validation failed: country must be a valid ISO 3166-1 alpha-2 code" | Field-level validation failed. |
400 | "Duplicate external_id" | An earlier call used the same external_id. |
400 | "No wallet for this country and currency" | You don’t own a wallet for the (country, currency) pair. |
400 | "Operator not available for this country/currency" | See Payment guidelines. |
401 | "Unauthorized" | Missing or expired token. |
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)
Related
GET /payment/transactions/{id}/status— poll for the outcome.POST /payment/payout— send money out via mobile money.- Payment guidelines — supported countries, operators, OTP/USSD requirements.
- Webhooks — full webhook catalogue.
Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Body
application/json
Available options:
mtn, orange, moov, airtel, mpesa, afrimoney, vodacom, wave, wligdicash, expresso, free, tmoney, celtiis, coris Example:
"mtn"
Pattern:
^[A-Z]{2}$Example:
"CM"
Example:
"237670000000"
Required range:
x >= 1Example:
1000
Example:
"XAF"
Example:
"https://example.com/webhook/payment"
Idempotency key (up to 255 chars). Duplicate values are rejected with 400 after the first call. Auto-generated if omitted.
Free-form reference shown in the dashboard (up to 255 chars).
Two-letter language code for operator-side prompts (e.g. en, fr).
Free-form description of the payment's purpose.