Initiate Payout
Create a payout to send funds to a beneficiary’s bank account via API.
Overview
Creates a payout for external partners via API. The system automatically handles FX conversion:- No pre-funding required - source currency can differ from destination currency
- FX conversion happens automatically
- Payouts start in
PENDINGstatus
- Attach at creation — upload via Get Document Upload URL, then pass
documentUrlassupportingDocument, or - Attach later — omit
supportingDocumenton initiate and use Add Supporting Documents before the payout is processed.
Required Headers
| Header | Required | Description |
|---|---|---|
Idempotency-Key | Yes | Client-generated unique key to prevent duplicate payouts. Generate using UUID or order ID before making the request. |
x-api-key | Yes | Your API key |
Request
Request Body
Request Fields
| Field | Type | Required | Description |
|---|---|---|---|
sourceAmount | number | Yes | Amount to debit from source wallet |
sourceCurrency | string | Yes | Source wallet currency (e.g., “NGN”, “USD”). Debit is always from this currency’s wallet—the system debits the business wallet that matches this currency. |
destinationCurrency | string | Yes | Destination currency (e.g., “CNY”, “NGN”) |
destinationCountryCode | string | Yes | ISO country code (3-letter ISO 3166-1 alpha-3, e.g., “CHN” for China, “NGA” for Nigeria, “USA” for United States) |
method | string | Yes | Payment method (e.g., “ALIPAY”, “SWIFT”, “NIP”) |
beneficiary | object | Yes | Beneficiary details (fields depend on method - see /methods endpoint) |
narration | string | Yes | Payment description |
supportingDocument | string (URL) | No* | HTTPS URL for an invoice. Use the documentUrl from POST /documents/upload-url after uploading the file to S3. Required for processing on most payouts; not required for withdrawals to your business account or a UBO’s account. May be attached at initiate or later via PATCH. |
remitterAddress | string | No | Optional top-level field on POST /initiate (not inside beneficiary). Provide the payer’s address when the remitter is not the business onboarded on Yala. When omitted, Yala assumes the onboarded business is the remitter and uses their verified address on file. Available for all payment methods; see optionalFields in GET /methods. |
accountName and accountCurrency. Required fields vary by payment method and are validated at the service level.
Key Points:
- ✅ Same structure for all methods - The beneficiary object always has the same fields available
- ✅ Method-specific requirements - Use
GET /methodsendpoint to discover which fields are required for your payment method - ✅ Automatic country derivation - If
beneficiary.countryCodeis not provided, it will be automatically derived fromdestinationCountryCodein the request body - ✅ Service-level validation - The API validates that all required fields for your selected method are present
accountName, accountCurrency, and alipayId. All other fields can be omitted.
Response
Response Fields
| Field | Type | Description |
|---|---|---|
id | string (UUID) | Payout identifier - Save this ID to track status via GET /:id or webhook notifications |
payoutRef | string | Human-readable payout reference |
sourceAmount | number | Amount debited from source wallet |
sourceCurrency | string | Source currency |
destinationAmount | number | Amount sent to beneficiary (after FX conversion) |
destinationCurrency | string | Destination currency |
exchangeRate | number | Actual exchange rate used for conversion - This is the rate that was applied at the time of payout initiation. If you previously viewed rates via GET /pairs or GET /methods, those rates were for reference only. Always check this field to confirm the rate that was actually used. |
transactionFees | number | Transaction fees (currently 0) |
status | string | One of: PENDING, ADDITIONAL_INFO_REQUIRED, PROCESSING, SUCCESSFUL, FAILED, REJECTED |
method | string | Payment method used |
narration | string | Payment description |
createdAt | string (ISO 8601) | Payout creation timestamp |
updatedAt | string (ISO 8601) | Last update timestamp |
Idempotency
How it works:-
Generate key client-side before making the request:
-
Include in header:
-
Retry with same key if request fails:
- Network error/timeout: Retry with same key + same body
- API returns original payout (no duplicate created)
- Same key + same request body: Returns existing payout (no duplicate)
- Same key + different request body:
409 Conflict(use a new key) - Missing key:
400 Bad Request
Error Responses
400 Bad Request - Missing Idempotency Key
400 Bad Request - Missing Required Fields
GET /methods endpoint to get required fields for your payment method. Required fields vary by method:
- ALIPAY:
accountName,alipayId - WECHAT:
accountName, and one of:openIdORwechatUserId - SEPA:
accountName,iban - SWIFT:
accountName,accountNumber,swiftCode(required),bankName,beneficiaryCountry(required),iban(optional),intermediarySwift(optional),address(optional),city(optional),postCode(optional) - ACH:
accountName,routingNumber,accountNumber,accountType(enum: “checking” or “savings”) - NIP:
accountName,accountNumber,bankCode - BACS/FASTER_PAYMENTS:
accountName,sortCode,accountNumber,iban(beneficiary) - HONG_KONG_FPS:
accountName, and one of:fpsIdORphoneNumberORemailOR (accountNumber+bankCode)
remitterAddress — use when the payer is not your onboarded business (see field table above).
400 Bad Request - Insufficient Funds
409 Conflict - Idempotency Key Reused
401 Unauthorized
Usage Example
Webhooks
When a payout’s status changes, we send a webhook notification to your configured endpoint. The webhook payload includes the payoutid so you can track which payout was updated.
To enable webhooks:
- Activate webhook notifications in your Yala dashboard
- Configure your webhook endpoint URL
- You’ll receive
payout.status.changed.v1events when status changes
payoutId- The payout ID (use this to match with your records)oldStatus- Previous statusnewStatus- New status (one ofPENDING,ADDITIONAL_INFO_REQUIRED,PROCESSING,SUCCESSFUL,FAILED,REJECTED)changedAt- Timestamp of status changereason- Human-readable reason for the change
Exchange Rate Behavior
Important: The exchange rate used for conversion is determined at the time of payout initiation.- Rate is fetched fresh - When you call
POST /initiate, the system fetches the current exchange rate from our rate database - Rate may differ from preview - If you previously viewed rates via
GET /pairsorGET /methods, those rates were for reference only. The actual rate applied may be different if rates changed between viewing and initiating - Check the response - The
exchangeRatefield in this response shows the rate that was actually used for your payout - Rate is not locked - There is no rate guarantee or locking mechanism. The rate used is whatever is current at initiation time
exchangeRate from the /initiate response to your users to show them the actual rate that was applied, rather than relying on rates shown in preview endpoints.
Notes
- FX Conversion: Happens automatically (no pre-funding required)
- Status: Payouts start in
PENDINGstatus - Field Validation: Beneficiary fields are validated against method requirements
- Tracking: Save the
idfield from the response to track payout status - Fees: Currently disabled
- Exchange Rate: Always check the
exchangeRatefield in the response to see the rate that was actually applied
Authorizations
Headers
"550e8400-e29b-41d4-a716-446655440000"
Body
Unique identifier for the business
"6fd2b69f-c529-4fe4-b680-29256f860553"
Amount in the source currency
1000
Source currency code
"USD"
Destination currency code
"NGN"
Payment method
SWIFT, NIP, HK_FPS, CHINA_WIRE, FASTER_PAYMENTS, WIRE, ACH, SEPA "NIP"
Destination country code
"NGA"
Transaction description
"Andromeda Galaxy"
URL to supporting document
"https://sample.com/doc"
Optional for all payment methods. Top-level payer address on the initiate body (not inside beneficiary). Provide when the remitter is not the business onboarded on Yala; when omitted, Yala uses the onboarded business verified address on file.
"10 Downing Street, London, SW1A 2AA"
Response
Payout initiated successfully