Skip to main content
POST
/
payment
/
payout
Initiate a payout
curl --request POST \
  --url https://api.cartevo.co/api/v1/payment/payout \
  --header 'Authorization: Bearer <token>' \
  --header 'Content-Type: application/json' \
  --data '
{
  "operator": "mtn",
  "country": "CM",
  "phone_number": "237670000000",
  "amount": 1000,
  "currency": "XAF",
  "notify_url": "https://example.com/webhook/payout",
  "external_id": "<string>",
  "reference_id": "<string>",
  "lang": "<string>",
  "purpose": "<string>"
}
'
{
  "success": true,
  "message": "Payout initiated successfully",
  "data": {
    "transaction_id": "550e8400-e29b-41d4-a716-446655440000",
    "external_id": "PAYOUT-1234567890-abc12345",
    "status": "PENDING",
    "amount": 1000,
    "currency": "XAF",
    "operator": "mtn",
    "country": "CM",
    "phone_number": "237670000000",
    "initiated_at": "2025-01-08T12:00:00.000Z",
    "error_message": "<string>"
  }
}

Overview

POST /payment/payout initiates a pay-out: it sends money from your company’s pay-out wallet to a mobile-money account. Cartevo:
  1. Calculates the total cost (amount + payout fee).
  2. Verifies the pay-out wallet has sufficient balance.
  3. Reserves the funds atomically.
  4. Submits the disbursement to the operator.
  5. If the disbursement fails permanently, automatically refunds the reserved funds back to your wallet.
The call returns immediately with status: PENDING; the final outcome reaches you via webhook (or via notify_url).

When to use it

  • Disburse salaries, payouts, refunds, or commissions to end users.
  • Power any “send money” feature in your product.
For the reverse direction (charging an end user), use POST /payment/collect.

Prerequisites

  • Your company has a wallet for the requested (country, currency) pair.
  • The wallet’s payout_balance is at least amount + fee. (Use POST /wallets/calculate-transfer-fees — currently undocumented — or estimate from your fee schedule.)
  • The combination of country, currency, and operator is supported — see Payment guidelines.

Request

Headers

NameRequiredDescription
AuthorizationYesBearer <access_token>
Content-TypeYesapplication/json

Body

FieldTypeRequiredConstraints / format
operatorstringYesOne of the supported operators — same enum as collection. Lowercase.
countrystringYesISO 3166-1 alpha-2, uppercase (e.g. CM).
phone_numberstringYesCountry code + local number, no + (e.g. 237670000000). Recipient phone number.
amountnumberYesMinimum 1. Major currency units. Excludes fees (the fee is added on top and deducted from your wallet).
currencystringYesISO 4217. Must match a wallet you own.
external_idstringNoIdempotency key. Up to 255 chars. Duplicates rejected with 400. Auto-generated if omitted.
notify_urlstringNoHTTPS URL to receive the final status webhook.
reference_idstringNoFree-form reference shown in the dashboard.
langstringNoTwo-letter language code.
purposestringNoFree-form description (e.g. "Salary May 2026").
{
  "operator": "mtn",
  "country": "CM",
  "phone_number": "237670000000",
  "amount": 50000,
  "currency": "XAF",
  "external_id": "PAYOUT-2026-001",
  "purpose": "Salary May 2026"
}

Response

200 — Payout initiated

{
  "success": true,
  "statusCode": 200,
  "message": "Payout initiated successfully",
  "data": {
    "transaction_id": "550e8400-e29b-41d4-a716-446655440000",
    "external_id": "PAYOUT-2026-001",
    "status": "PENDING",
    "amount": 50000,
    "currency": "XAF",
    "operator": "mtn",
    "country": "CM",
    "phone_number": "237670000000",
    "initiated_at": "2026-05-09T10:15:00.000Z",
    "error_message": null
  }
}
FieldDescription
transaction_idCartevo transaction ID (UUID).
external_idEchoes your idempotency key (or auto-generated).
statusOne of PENDING, PROCESSING, SUCCESS, FAILED.
error_messageAlways null on initiation. Populated on failure (poll the status endpoint or wait for the webhook).

Lifecycle and atomic behavior

                                ┌──── operator accepts ────→ SUCCESS
PENDING → PROCESSING ──────────→
        (funds reserved)        └──── operator rejects ────→ FAILED (funds auto-refunded)
  • On PENDING / PROCESSING: the funds are reserved in your wallet but not yet visible as deducted.
  • On SUCCESS: the reserved funds are released to the operator. The recipient is credited.
  • On FAILED: the reserved funds are returned to your wallet automatically. No manual reconciliation needed.

Error responses

Statusmessage exampleTrigger
400"Insufficient balance (including fees)"Pay-out wallet has less than amount + fee.
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

  • A status-update webhook is sent on each transition (PENDINGPROCESSINGSUCCESS/FAILED).
  • If you supplied notify_url, it receives the same updates.

Code examples

cURL
curl -X POST https://api.cartevo.co/api/v1/payment/payout \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
    "operator": "mtn",
    "country": "CM",
    "phone_number": "237670000000",
    "amount": 50000,
    "currency": "XAF",
    "external_id": "PAYOUT-2026-001"
  }'
Node.js (axios)
await axios.post(
  "https://api.cartevo.co/api/v1/payment/payout",
  {
    operator: "mtn",
    country: "CM",
    phone_number: "237670000000",
    amount: 50000,
    currency: "XAF",
    external_id: `PAYOUT-${Date.now()}`,
    notify_url: "https://your-app.com/webhooks/cartevo",
  },
  { headers: { Authorization: `Bearer ${token}` } }
);

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/payout"

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 payout's purpose.

Response

Payout initiated successfully

success
boolean
Example:

true

message
string
Example:

"Payout initiated successfully"

data
object