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

# Initiate Payout

> Send money to a customer using Waftpay Payouts API.

## Overview

Use the Payouts API to disburse funds from your Waftpay wallet to a customer, vendor, or partner. Payouts are asynchronous: you receive an acceptance response immediately, then a final outcome via webhook.

This call is **idempotent**. Reuse the same `transaction.reference` to safely retry the same logical payout.

***

## Authentication and signature

**Required headers**

| Header               | Required | Notes                                                                                           |
| -------------------- | -------- | ----------------------------------------------------------------------------------------------- |
| `Authorization`      | Yes      | `Bearer <payout_token>` (payout product token only)                                             |
| `X-Custom-Signature` | Yes      | Base64 RSA signature. See [Signature generation](/api-reference/signatures/signature-generate). |
| `Content-Type`       | Yes      | `application/json`                                                                              |

***

## Request body

**Top-level fields**

| Field          | Type   | Required | Notes                                             |
| -------------- | ------ | -------- | ------------------------------------------------- |
| `transaction`  | object | Yes      | Payout details and idempotency reference.         |
| `originator`   | object | Yes      | Sender details.                                   |
| `recipient`    | object | Yes      | Recipient details.                                |
| `callback_url` | string | Yes      | HTTPS URL for final status callbacks.             |
| `meta`         | object | No       | Arbitrary key/value metadata echoed in callbacks. |

**transaction**

| Field          | Type    | Required | Notes                                                |
| -------------- | ------- | -------- | ---------------------------------------------------- |
| `reference`    | string  | Yes      | Client-generated unique reference (idempotency key). |
| `amount`       | integer | Yes      | Amount in major units (e.g., 1000 = 1000 KES).       |
| `currency`     | string  | Yes      | ISO 4217 currency code (e.g., KES, USD).             |
| `description`  | string  | Yes      | Short narrative for the payout.                      |
| `service_code` | string  | Yes      | Service to use (e.g., MPESAB2C).                     |
| `timestamp`    | string  | Yes      | ISO 8601 UTC timestamp (must end with `Z`).          |

**originator**

| Field     | Type   | Required | Notes                                 |
| --------- | ------ | -------- | ------------------------------------- |
| `msisdn`  | string | Yes      | MSISDN format (e.g., 2547XXXXXXXX).   |
| `channel` | string | Yes      | Initiation channel (e.g., USSD, API). |
| `country` | string | Yes      | ISO 3166-1 country code (e.g., KE).   |
| `name`    | string | Yes      | Originator name.                      |
| `purpose` | string | Yes      | Reason for the payout.                |

**recipient**

| Field              | Type   | Required | Notes                                                       |
| ------------------ | ------ | -------- | ----------------------------------------------------------- |
| `reference`        | string | Yes      | Client-generated reference for recipient-side tracking.     |
| `account`          | string | Yes      | Recipient account identifier (phone, wallet, bank account). |
| `name`             | string | Yes      | Recipient full name.                                        |
| `destination_code` | string | Yes      | Destination code for the recipient corridor or payout rail. |

***

## Example request

```json theme={null}
{
  "transaction": {
    "reference": "TXN213687756272200",
    "amount": 1000,
    "currency": "KES",
    "description": "Vendor payout",
    "service_code": "MPESAB2C",
    "timestamp": "2025-01-21T12:30:10Z"
  },
  "originator": {
    "msisdn": "254708374149",
    "channel": "USSD",
    "country": "KE",
    "name": "Payment",
    "purpose": "Transaction Payment"
  },
  "recipient": {
    "reference": "INVJMA02",
    "account": "254708374149",
    "name": "John Doe Init",
    "destination_code": "300213"
  },
  "callback_url": "https://merchant.example.com/callbacks/payout",
  "meta": {
    "note": "This info is returned as part of the callback",
    "agent_id": "AGENT458"
  }
}
```

***

## Example response (accepted)

```json theme={null}
{
  "code": "100",
  "status": "ACCEPTED",
  "description": "Accepted for processing",
  "data": {
    "amount": 100,
    "transaction_reference": "919938",
    "payment_uuid": "413283551143664292",
    "payment_reference": "351CSICLV0",
    "time_received": "2026-01-07T09:44:43.558023Z"
  }
}
```

***

## Notes

* Final outcome is delivered via webhook. See [Webhooks overview](/pages/webhooks/overview).
* Errors follow the standard error shape. See [Errors](/errors).


## OpenAPI

````yaml POST /payments/api/v1/payouts
openapi: 3.1.0
info:
  title: Waftpay Payments API
  description: >-
    Process payments, collect funds, and remit payouts with Waftpay. Includes
    Authentication Token, idempotency, webhooks, and sandbox support.
  license:
    name: MIT
  version: 1.0.0
servers:
  - url: https://dev.waftpay.io
    description: Sandbox (dev)
security:
  - bearerAuth: []
tags:
  - name: Authentication
    description: Obtain and manage access tokens
  - name: Payments
    description: Charge a customer and track status
  - name: Collections
    description: Customer-initiated payments and hosted checkouts
  - name: Checkout
    description: >-
      Hosted checkout flow for customer payments.


      Flow:

      1. Ensure the Collections service is enabled for your account.

      2. Use `consumer_key` and `consumer_secret` to generate a Bearer token via
      **Get Authentication Token**.

      3. Cache the token and refresh only on expiry.

      4. Call **Create Checkout Request** with customer details, amount, and
      redirect URLs.

      5. Use the returned `checkout_url` for redirect or iframe.

      6. The `callback_url` receives a payload matching the `CheckoutCallback`
      schema.
  - name: Remittance
    description: Send payouts to mobile wallets and bank accounts
  - name: Webhooks
    description: Receive asynchronous notifications
  - name: Utilities
    description: Common utilities (idempotency, health)
paths:
  /payments/api/v1/payouts:
    post:
      tags:
        - Payouts
      summary: Initiate Payout
      operationId: initiatePayout
      parameters:
        - $ref: '#/components/parameters/XCustomSignature'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/CreatePayoutRequestV2'
            examples:
              default:
                value:
                  transaction:
                    reference: TXN213687756272200
                    amount: 1000
                    currency: KES
                    description: Test description
                    service_code: MPESAB2C
                    timestamp: '2025-01-21T12:30:10Z'
                  originator:
                    msisdn: '254708374149'
                    channel: USSD
                    country: KE
                    name: John Doe
                    purpose: Salary Payment
                  recipient:
                    reference: INVJMA02
                    account: '254708374149'
                    name: John Doe Init
                    destination_code: '300213'
                  callback_url: https://merchant.example.com/callbacks/payout
                  meta: {}
      responses:
        '201':
          description: Accepted
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PayoutInitiationResponse'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
components:
  parameters:
    XCustomSignature:
      name: X-Custom-Signature
      in: header
      required: true
      schema:
        type: string
      description: >-
        Base64 RSA signature over: transaction.reference + transaction.amount +
        originator.country + transaction.service_code
  schemas:
    CreatePayoutRequestV2:
      type: object
      required:
        - transaction
        - originator
        - recipient
        - callback_url
      properties:
        transaction:
          type: object
          required:
            - reference
            - amount
            - currency
            - description
            - service_code
            - timestamp
          properties:
            reference:
              type: string
              description: >-
                Client-generated unique reference (idempotency key). Reuse to
                safely retry.
            amount:
              type: integer
              description: Amount in major units (e.g., 1000 = 1000 KES).
            currency:
              type: string
              description: ISO 4217 currency code in upper-case, e.g., KES, USD.
            description:
              type: string
              description: Short narrative for the payout.
            service_code:
              type: string
              description: Service the client wants to consume (e.g., MPESAB2C).
            timestamp:
              type: string
              format: date-time
              description: ISO 8601 UTC timestamp. (e.g., 2025-01-21T12:30:10Z).
        originator:
          type: object
          required:
            - msisdn
            - channel
            - country
            - name
            - purpose
          properties:
            msisdn:
              type: string
              description: Originator phone number in MSISDN format (e.g., 2547XXXXXXXX).
            channel:
              type: string
              description: Channel used to initiate the payout (e.g., USSD, API).
            country:
              type: string
              description: >-
                Country code (ISO 3166-1 alpha-2 like 'KE' or alpha-3 like
                'KEN'). Use what's configured on your account.
            name:
              type: string
              description: Originator name - preferable two names (e.g., Alvin Muriithi
            purpose:
              type: string
              description: Originator purpose or reason for payout
        recipient:
          type: object
          required:
            - reference
            - account
            - name
            - destination_code
          properties:
            reference:
              type: string
              description: >-
                Client-generated unique reference (idempotency key). Reuse to
                safely retry.
            account:
              type: string
              description: Recipient account identifier (phone, wallet, bank acct).
            name:
              type: string
              description: Recipient full name.
            destination_code:
              type: string
              description: Destination code for the recipient corridor or payout rail.
        callback_url:
          type: string
          format: uri
          description: HTTPS URL to receive final status callbacks.
        meta:
          type: object
          description: Arbitrary key-value metadata echoed back in callbacks.
          additionalProperties: true
      examples:
        - transaction:
            reference: TXN213687756272200
            amount: 1000
            currency: KES
            description: Vendor payout
            service_code: MPESAB2C
            timestamp: '2025-01-21T12:30:10Z'
          originator:
            msisdn: '254708374149'
            channel: USSD
            country: KE
            name: Payment
            purpose: Transaction Payment
          recipient:
            reference: INVJMA02
            account: '254708374149'
            name: John Doe Init
            destination_code: '300213'
          callback_url: https://merchant.example.com/callbacks/payout
          meta:
            note: This info is returned as part of the callback
            agent_id: AGENT458
    PayoutInitiationResponse:
      type: object
      required:
        - status
        - code
        - description
        - data
      properties:
        status:
          type: string
          description: e.g., 200.100
        code:
          type: string
          description: ACCEPTED, REJECTED.
        description:
          type: string
        data:
          type: object
          required:
            - amount
            - transaction_reference
            - payment_uuid
            - payment_reference
            - time_received
          properties:
            amount:
              type: number
            transaction_reference:
              type: string
            payment_uuid:
              type: string
              description: UUID or numeric string identifier.
            payment_reference:
              type: string
            time_received:
              type: string
              format: date-time
              description: ISO 8601 UTC timestamp. **Always ends with 'Z'**.
          additionalProperties: true
      examples:
        accepted:
          summary: Accepted for processing
          value:
            status: '200.100'
            code: ACCEPTED
            description: Accepted for processing
            data: {}
        duplicateIgnored:
          summary: Duplicate ignored
          value:
            status: '200.100'
            code: REJECTED
            description: Duplicate payout ignored
            data: {}
        rejected:
          summary: Rejected
          value:
            status: '400.100'
            code: REJECTED
            description: Invalid recipient account number
            data: null
    Error:
      type: object
      required:
        - error
        - message
      properties:
        error:
          type: string
          description: Machine readable error code
        message:
          type: string
          description: Human readable message
        param:
          type: string
        request_id:
          type: string
    WaftpayErrorEnvelope:
      type: object
      required:
        - code
        - status
        - description
      properties:
        code:
          type: string
          description: >-
            Application code. Can be a top-level code (e.g., 400.600) or a
            granular code (e.g., 404.001.000).
        status:
          type: string
          description: >-
            Semantic status, e.g., REJECTED, FAILED, UNAUTHORIZED, FORBIDDEN,
            NOT_FOUND, ACCEPTED.
        description:
          type: string
          description: Human-readable description.
        data:
          type: object
          description: Additional details (may be empty).
          additionalProperties: true
          nullable: true
      examples:
        notFoundGranular:
          summary: 404 with granular code
          value:
            code: 404.001.000
            status: REJECTED
            description: Requested resource not found
            data: {}
        validationFailed:
          summary: 400 validation failed
          value:
            code: '400.100'
            status: REJECTED
            description: Validation failed
            data:
              field_errors:
                - field: recipient.account
                  message: Invalid account
        unauthorized:
          summary: 401 failed authentication
          value:
            code: '400.200'
            status: REJECTED
            description: Failed Authentication
            data: null
        forbidden:
          summary: 403 failed authorization
          value:
            code: '403.300'
            status: REJECTED
            description: Failed Authorization
            data: null
        internal:
          summary: 500 internal server error
          value:
            code: '400.500'
            status: FAILED
            description: Internal server error
            data: null
  responses:
    BadRequest:
      description: Bad request
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
    Unauthorized:
      description: Missing or invalid token
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/WaftpayErrorEnvelope'
          examples:
            unauthorized:
              value:
                code: 400.001.100
                status: REJECTED
                description: Invalid or expired token
                data: {}
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

````