Skip to navigation

Single Payouts

Send individual payouts to recipients

Single payouts allow you to send funds to one recipient at a time. This is ideal for one-off transactions, refunds, or when you need to process payouts individually.

When to Use Single Payouts

  • One-time payments to individual recipients
  • Refunds or customer disbursements
  • Small-scale operations
  • Testing and development

Creating a Single Payout

To create a single payout, you’ll need:

  1. merchantId: Your merchant identifier
  2. merchantReference: Your internal reference for tracking and idempotency
  3. destinationValue: Object with:
    • minorAmount: Amount in minor units (integer, e.g., 10000 = 100.00 NGN). See Amount Format below.
    • currency: Must be a supported payout currency (NGN, XOF, XAF, GHS, KES, TZS, UGX, ZAR, EGP — availability depends on the processors configured on your account)
  4. paymentMethodId: "banktransfer", "mobilemoney", "cash", or "institutionwallet" (note: no underscore, unlike the matching recipient.type)
  5. paymentLocation: 3-letter ISO country code (e.g., NGA, KEN, EGY)
  6. Destination — supply either recipient (inline details) or payoutBeneficiaryId (reference to a pre-registered, pre-validated recipient). The two are mutually exclusive. See Choosing a Destination below.
  7. sender: Sender details for KYT/KYC screening — fullName, identity (document type, e.g. passport or nationalId), and identityNumber are required for all payouts; some destinations require additional fields (see the market pages)
  8. attributes (optional): Key-value map for additional payout metadata or provider-specific options. Pass {} if not needed. See the API reference for supported keys per destination.

Choosing a Destination

Each payout names its destination in one of two ways. Pick one — they are mutually exclusive on a single request.

  • Inline recipient — supply the recipient’s account details (bank account or mobile wallet) directly on every payout call. Details are validated synchronously at payout time. Fastest path for one-off payouts.
  • payoutBeneficiaryId — pre-register the recipient once with POST /v1/payout-beneficiaries. CrissCross verifies the destination against the receiving network and runs AML pre-screening up front; once it reaches status: approved you reference it by payoutBeneficiaryId on every subsequent payout. This shrinks the per-call payload, surfaces verification failures before a payout is attempted, and prevents accidental detail drift between repeat payouts to the same recipient.

For the full registration, lifecycle, and signal flow, see Payout Beneficiaries.

Recipient field shapes — used when supplying recipient inline:

  • For bank accounts: type: "bank_account", accountNumber, bankCode, accountHolderName, country, optional phoneNumber
  • For mobile wallets: type: "mobile_money", phoneNumber, country, operator, optional name
  • For cash pickup: type: "cash", fullName, country, optional phoneNumber
  • For institution wallets: type: "institution_wallet", fullName, country, optional phoneNumber

Amount Format

Amounts are specified in minor units (the smallest currency unit, like cents). The minorAmount field is an integer.

Examples:

  • 10000 minorAmount = 100.00 NGN (Nigerian Naira, 2 decimal places)
  • 5000 minorAmount = 50.00 KES (Kenyan Shillings, 2 decimal places)
  • 5000 minorAmount = 5,000 XOF (CFA franc has no minor unit — the integer is the whole-unit amount)

Important: The number of decimal places follows the currency’s ISO 4217 exponent. Most currencies have 2, but XOF, XAF, UGX, RWF, BIF, and GNF have none — for those, no multiplication applies.

Request Examples

Bank Account Payout

{
"merchantId": "your-merchant-id",
"merchantReference": "PAYOUT-2024-001",
"destinationValue": {
"minorAmount": 1000000,
"currency": "NGN"
},
"paymentMethodId": "banktransfer",
"paymentLocation": "NGA",
"recipient": {
"type": "bank_account",
"accountNumber": "0123456789",
"bankCode": "044",
"accountHolderName": "John Doe",
"country": "NGA"
},
"sender": {
"fullName": "Jane Smith",
"identity": "passport",
"identityNumber": "A12345678"
},
"attributes": {}
}

Note: minorAmount: 1000000 = 10,000.00 NGN (NGN has 2 decimal places).

Mobile Wallet Payout

{
"merchantId": "your-merchant-id",
"merchantReference": "PAYOUT-2024-002",
"destinationValue": {
"minorAmount": 500000,
"currency": "KES"
},
"paymentMethodId": "mobilemoney",
"paymentLocation": "KEN",
"recipient": {
"type": "mobile_money",
"phoneNumber": "254712345678",
"country": "KEN",
"operator": "mpesa",
"name": "Jane Smith"
},
"sender": {
"fullName": "Jane Smith",
"phoneNumber": "27821234567",
"nationality": "ZAF",
"identity": "passport",
"identityNumber": "A12345678",
"dateOfBirth": "1990-01-15",
"purposeOfFunds": "salary",
"sourceOfFunds": "business income",
"relationship": "employer"
},
"attributes": {}
}

Note: minorAmount: 500000 = 5,000.00 KES. Kenya payouts require additional sender fields — see Kenya.

Payout Against a Pre-Registered Beneficiary

When the recipient was registered ahead of time via POST /v1/payout-beneficiaries, drop recipient and reference the beneficiary by payoutBeneficiaryId instead. Every other field on the request is unchanged.

{
"merchantId": "your-merchant-id",
"merchantReference": "PAYOUT-2024-004",
"destinationValue": {
"minorAmount": 5000000,
"currency": "UGX"
},
"paymentMethodId": "mobilemoney",
"paymentLocation": "UGA",
"payoutBeneficiaryId": "f47ac10b-58cc-4372-a567-0e02b2c3d479",
"sender": {
"fullName": "Jane Smith",
"identity": "passport",
"identityNumber": "A12345678"
},
"attributes": {}
}

Note: The referenced beneficiary must be in status: approved — a payout that references a pending_review, rejected, or failed beneficiary is rejected with 422. See Payout Beneficiaries for the full registration and lifecycle.

Response Structure

Successful Response

A successful payout response (HTTP 201) includes:

{
"status": "PENDING",
"transactionId": "payout_9f8b7c6d5e4a3b2c1d0e",
"message": "Payout transaction initiated successfully",
"merchantReference": "PAYOUT-2024-001",
"paymentMethodId": "banktransfer",
"processorReference": "PROC-123456"
}

Response fields:

  • status: Current status (PENDING, PROCESSING, COMPLETED, FAILED, CANCELLED)
  • transactionId: Unique transaction identifier
  • message: Status message
  • merchantReference: Your provided merchant reference (if supplied)
  • sessionId: Session ID (if applicable)
  • identifiers: Additional identifiers related to the transaction
  • paymentAttributes: Payment-specific attributes and metadata
  • paymentMethodId: Payment method identifier
  • processorName: Payment processor name
  • processorReference: Payment processor reference
  • financialTransactionReference: Financial transaction reference from the processor
  • currentAttemptId: Current attempt identifier
  • batchPayoutId: Batch payout identifier, if part of a bulk payout

Payout Statuses

  • PENDING: Payout has been created and is awaiting processing
  • PROCESSING: Payout is currently being processed
  • COMPLETED: Payout has been successfully completed
  • FAILED: Payout has failed (check message, identifiers, and paymentAttributes for details)
  • CANCELLED: Payout was cancelled

Error Handling

The API returns standard HTTP status codes:

  • 201: Payout transaction initiated successfully
  • 400: Bad Request - Invalid payout parameters or insufficient balance
  • 401: Unauthorized - Invalid or missing authentication
  • 422: Request validation failed
  • 500: Internal server error

Error Response Structure

Error responses (HTTP 400, 401, 422) include an error object with code and message fields:

{
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient balance in payout source account"
}
}

Example error responses:

Insufficient Balance (400):

{
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Insufficient balance in payout source account"
}
}

Invalid Parameters (400):

{
"error": {
"code": "INVALID_REQUEST",
"message": "Invalid recipient details provided"
}
}

Unauthorized (401):

{
"error": {
"code": "UNAUTHORIZED",
"message": "Invalid or expired access token"
}
}

Common error codes:

  • INSUFFICIENT_BALANCE: Not enough funds in the payout currency
  • INVALID_REQUEST: Invalid request parameters (e.g., invalid currency, missing required fields)
  • INVALID_RECIPIENT: Invalid recipient details (e.g., invalid account number, phone number)
  • UNAUTHORIZED: Invalid or expired access token
  • RATE_LIMIT_EXCEEDED: Too many requests (see Rate Limiting)

Example Use Cases

  • Refund Processing: Send refunds to customers who returned products
  • Vendor Payments: Pay individual suppliers or service providers
  • Customer Rewards: Distribute loyalty rewards or cashback
  • One-off Disbursements: Send individual payments as needed

Idempotency

Each payout must use a merchantReference that is unique within your merchant account. The reference guards against accidental duplicate payouts.

If you initiate a payout with a merchantReference that was already used by a previous payout, the request is rejected with a DUPLICATE_REFERENCE error (HTTP 409 Conflict). The API does not create a second payout, and it does not replay or return the original payout. This protects you from sending the same payout twice if a request is retried after a network error or timeout.

Uniqueness is enforced per merchant account and does not expire — a merchantReference cannot be reused once it has been accepted, regardless of how much time has passed.

Safely retrying: If you don’t know whether a request succeeded (e.g. a timeout), retry it with the same merchantReference. A 409 Conflict confirms the original payout was already accepted — look it up via the history endpoints rather than resending. Any other error means the payout was not created and is safe to retry.

Best practice: Generate a unique, meaningful reference for each payout (e.g., PAYOUT-2024-001, REFUND-ORDER-12345) and store it alongside the returned transaction ID for reconciliation.

Best Practices

  • Always verify recipient details before initiating payouts
  • Use unique, meaningful references for idempotency and easy tracking
  • Monitor payout status through the history endpoints or webhooks
  • Ensure sufficient balance before initiating payouts
  • Handle failed payouts by checking status, message, and any returned identifiers or paymentAttributes
  • Store payout IDs and references for reconciliation and tracking
  • Implement retry logic with exponential backoff for transient failures

For detailed API documentation, see the Payouts API Reference.