> ## Documentation Index
> Fetch the complete documentation index at: https://developer.cartevo.co/llms.txt
> Use this file to discover all available pages before exploring further.

# Initiate Payout

> Send money from your company's pay-out wallet to a mobile-money account. Calculates and applies fees, deducts atomically, and auto-refunds on failure.

## 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`](/api-reference/endpoint/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`](/api-reference/endpoint/get-payment-balance) — currently undocumented — or estimate from your fee schedule.)
* The combination of `country`, `currency`, and `operator` is supported — see [Payment guidelines](/api-reference/endpoint/payment_guide_lines).

## 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 the supported operators — same enum as collection. Lowercase.                                      |
| `country`      | string | Yes      | ISO 3166-1 alpha-2, **uppercase** (e.g. `CM`).                                                            |
| `phone_number` | string | Yes      | Country code + local number, **no `+`** (e.g. `237670000000`). Recipient phone number.                    |
| `amount`       | number | Yes      | Minimum `1`. Major currency units. Excludes fees (the fee is added on top and deducted from your wallet). |
| `currency`     | string | Yes      | ISO 4217. Must match a wallet you own.                                                                    |
| `external_id`  | string | No       | **Idempotency key.** Up to 255 chars. Duplicates rejected with `400`. Auto-generated if omitted.          |
| `notify_url`   | string | No       | HTTPS URL to receive the final status webhook.                                                            |
| `reference_id` | string | No       | Free-form reference shown in the dashboard.                                                               |
| `lang`         | string | No       | Two-letter language code.                                                                                 |
| `purpose`      | string | No       | Free-form description (e.g. `"Salary May 2026"`).                                                         |

```json theme={null}
{
  "operator": "mtn",
  "country": "CM",
  "phone_number": "237670000000",
  "amount": 50000,
  "currency": "XAF",
  "external_id": "PAYOUT-2026-001",
  "purpose": "Salary May 2026"
}
```

## Response

### 200 — Payout initiated

```json theme={null}
{
  "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
  }
}
```

| Field            | Description                                                                                           |
| ---------------- | ----------------------------------------------------------------------------------------------------- |
| `transaction_id` | Cartevo transaction ID (UUID).                                                                        |
| `external_id`    | Echoes your idempotency key (or auto-generated).                                                      |
| `status`         | One of `PENDING`, `PROCESSING`, `SUCCESS`, `FAILED`.                                                  |
| `error_message`  | Always `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

| Status | `message` example                                    | Trigger                                                                |
| ------ | ---------------------------------------------------- | ---------------------------------------------------------------------- |
| `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](/api-reference/endpoint/payment_guide_lines). |
| `401`  | `"Unauthorized"`                                     | Missing or expired token.                                              |

## Webhooks fired

* A status-update webhook is sent on each transition (`PENDING` → `PROCESSING` → `SUCCESS`/`FAILED`).
* If you supplied `notify_url`, it receives the same updates.

## Code examples

```bash cURL theme={null}
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"
  }'
```

```js Node.js (axios) theme={null}
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}` } }
);
```

## Related

* [`POST /payment/collect`](/api-reference/endpoint/post-payment-collect) — the reverse direction.
* [`GET /payment/transactions/{id}/status`](/api-reference/endpoint/get-payment-transaction-status) — poll for the outcome.
* [`GET /payment/balance`](/api-reference/endpoint/get-payment-balance) — check your pay-out wallet balance before calling.


## OpenAPI

````yaml POST /payment/payout
openapi: 3.1.0
info:
  title: Cartevo API
  description: Essential endpoints for wallets, transactions, customers and conversion.
  version: 1.0.0
servers:
  - url: https://api.cartevo.co/api/v1
security:
  - bearerAuth: []
paths:
  /payment/payout:
    post:
      summary: Initiate a payout
      description: >-
        Initiate a payout (money disbursement). This endpoint validates wallet
        balance (including fees), calculates and applies withdrawal fees,
        deducts balance from wallet atomically, and automatically refunds on
        failure. Works like WalletWithdrawalService.processWithdrawal() with
        comprehensive error handling and logging.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                operator:
                  type: string
                  enum:
                    - mtn
                    - orange
                    - moov
                    - airtel
                    - mpesa
                    - afrimoney
                    - vodacom
                    - wave
                    - wligdicash
                    - expresso
                    - free
                    - tmoney
                    - celtiis
                    - coris
                  example: mtn
                country:
                  type: string
                  pattern: ^[A-Z]{2}$
                  example: CM
                phone_number:
                  type: string
                  example: '237670000000'
                amount:
                  type: number
                  minimum: 1
                  example: 1000
                currency:
                  type: string
                  example: XAF
                notify_url:
                  type: string
                  example: https://example.com/webhook/payout
                external_id:
                  type: string
                  description: >-
                    Idempotency key (up to 255 chars). Duplicate values are
                    rejected with 400 after the first call. Auto-generated if
                    omitted.
                reference_id:
                  type: string
                  description: >-
                    Free-form reference shown in the dashboard (up to 255
                    chars).
                lang:
                  type: string
                  description: >-
                    Two-letter language code for operator-side prompts (e.g. en,
                    fr).
                purpose:
                  type: string
                  description: Free-form description of the payout's purpose.
              required:
                - operator
                - country
                - phone_number
                - amount
                - currency
      responses:
        '200':
          description: Payout initiated successfully
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  message:
                    type: string
                    example: Payout initiated successfully
                  data:
                    $ref: '#/components/schemas/PayoutResponse'
        '400':
          description: Bad request - validation error or insufficient balance
          content:
            application/json:
              schema:
                type: object
                properties:
                  statusCode:
                    type: integer
                    example: 400
                  message:
                    type: string
                    example: >-
                      Insufficient payout balance. Required: 1020 XAF (including
                      fees)
                  error:
                    type: string
                    example: Bad Request
        '401':
          description: Unauthorized - invalid or missing authentication token
components:
  schemas:
    PayoutResponse:
      type: object
      properties:
        transaction_id:
          type: string
          format: uuid
          example: 550e8400-e29b-41d4-a716-446655440000
        external_id:
          type: string
          example: PAYOUT-1234567890-abc12345
        status:
          type: string
          enum:
            - PENDING
            - SUCCESS
            - FAILED
            - PROCESSING
          example: PENDING
        amount:
          type: number
          example: 1000
        currency:
          type: string
          example: XAF
        operator:
          type: string
          example: mtn
        country:
          type: string
          example: CM
        phone_number:
          type: string
          example: '237670000000'
        initiated_at:
          type: string
          format: date-time
          example: '2025-01-08T12:00:00.000Z'
        error_message:
          type: string
          nullable: true
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer

````