### API Validation Error with Details Example Source: https://docs.wave.com/payout/index_payout-api This example shows a more detailed validation error, specifically for an unknown currency identifier. It includes a 'details' array providing location, message, and type of the validation failure. ```json { "code": "request-validation-error", "message": "Request invalid", "details": [ { "loc": ["currency"], "msg": "Unknown currency identifier: ABC. We require the currency to be a three-letter ISO 4217 code.", "type": "value_error" } ] } ``` -------------------------------- ### Payout API Request and Response Examples Source: https://docs.wave.com/payout/index Demonstrates the structure of a successful payout request and its corresponding response, including fields like ID, currency, amount, fee, and status. It also shows an example of an error response with a code and message. ```json { "id": "pt-185b5e4b8100c", "currency": "XOF", "receive_amount": "500", "fee": "5", "mobile": "+221555110219", "name": "Fatou Ndiaye", "status": "succeeded", "timestamp": "2022-06-20T17:17:11Z" } ``` ```json { "code": "request-validation-error", "message": "An 'Idempotency-Key' header is required for POST requests" } ``` -------------------------------- ### Verify Recipient Response Example Source: https://docs.wave.com/payout/index_payout-api An example response body for the verify recipient endpoint. It indicates whether the payout is within limits, if the provided name matches records, and if the national ID matches. If currency and amount are not set, `within_limits` will be null. ```json { "within_limits": true, "name_match": "NAME_NOT_KNOWN", "national_id_match": "NO_MATCH" } ``` -------------------------------- ### GET /v1/payouts/search Source: https://docs.wave.com/payout/index Search for payouts based on various criteria. ```APIDOC ## GET /v1/payouts/search ### Description Search for payouts based on various criteria. ### Method GET ### Endpoint https://api.wave.com/v1/payouts/search ### Parameters #### Query Parameters - **status** (string) - Optional - Filter payouts by status (e.g., "pending", "completed", "failed"). - **recipient_mobile** (string) - Optional - Filter payouts by recipient's mobile number. - **limit** (integer) - Optional - The maximum number of results to return. - **offset** (integer) - Optional - The number of results to skip. #### Header Parameters - **Authorization** (string) - Required - Bearer token with your API key. ### Response #### Success Response (200) - **payouts** (array) - A list of payout objects matching the search criteria. - Each object contains: `payout_id`, `status`, `amount`, `currency`, `recipient_name`, `recipient_mobile`, `created_at`. #### Response Example ```json { "payouts": [ { "payout_id": "po_12345abcde", "status": "completed", "amount": "500", "currency": "XOF", "recipient_name": "Fatou Ndiaye", "recipient_mobile": "+221555110219", "created_at": "2023-10-27T10:00:00Z" }, { "payout_id": "po_67890fghij", "status": "pending", "amount": "1000", "currency": "XOF", "recipient_name": "Moussa Traore", "recipient_mobile": "+221555987654", "created_at": "2023-10-27T11:00:00Z" } ] } ``` ``` -------------------------------- ### Idempotency Key Generation Examples Source: https://docs.wave.com/payout/index Demonstrates how to generate idempotency keys across different programming languages and shell commands. These keys ensure safe retries for modifying requests. ```shell openssl rand -hex 8 ``` ```php $idem_key = uniqid(more_entropy: True) ``` ```python import uuid idem_key = str(uuid.uuid4()) ``` ```javascript let idem_key = crypto.randomUUID(); ``` -------------------------------- ### GET /v1/payouts/search Source: https://docs.wave.com/payout/index Retrieves a list of payouts based on the provided query parameters. Currently supports only search by client reference (`client_reference`). ```APIDOC ## GET /v1/payouts/search ### Description Retrieves a list of payouts based on the provided query parameters. Currently supports only search by client reference (`client_reference`). ### Method GET ### Endpoint /v1/payouts/search #### Query Parameters - **client_reference** (string) - Required - The client reference to search payouts by. ### Request Example ``` curl -X GET \ --url https://api.wave.com/v1/payouts/search?client_reference=FAH.4827.1734 \ -H 'Authorization : Bearer wave_sn_prod_YhUNb9d...i4bA6' ``` ### Response #### Success Response (200) - **result** (List of payouts) - The list of payouts that match the search criteria. #### Response Example ```json { "result": [ { "id": "pt-185sewgm8100t", "currency": "XOF", "receive_amount": "15000", "fee": "150", "mobile": "+221555110233", "name": "Moustapha Mbaye", "national_id": "1751197904376", "client_reference": "FAH.4827.1734", "payment_reason": "Salary November 2022", "status": "succeeded", "timestamp": "2022-06-21T09:56:29Z", "aggregated_merchant_id": "am-7lks22ap113t4" } ] } ``` ``` -------------------------------- ### Create Single Payout Request (curl) Source: https://docs.wave.com/payout/index Example using curl to send a POST request to the /v1/payout endpoint. It includes the necessary Authorization, Content-Type, and idempotency-key headers, along with the payout details in JSON format. ```shell curl -X POST \ --url https://api.wave.com/v1/payout \ -H 'Authorization: Bearer wave_sn_prod_YhUNb9d...i4bA6' \ -H 'Content-Type: application/json' \ -H 'idempotency-key: 65f735b4-b44b-429d-b0a8-550701e2393a' \ -d '{ "currency": "XOF", "receive_amount": "500", "name": "Fatou Ndiaye", "mobile": "+221555110219" }' ``` -------------------------------- ### GET /v1/payouts-batch/:id Source: https://docs.wave.com/payout/index Retrieve the status and details of a batch payout. ```APIDOC ## GET /v1/payouts-batch/:id ### Description Retrieve the status and details of a batch payout. ### Method GET ### Endpoint https://api.wave.com/v1/payouts-batch/:id ### Parameters #### Path Parameters - **id** (string) - Required - The unique identifier of the batch payout. #### Header Parameters - **Authorization** (string) - Required - Bearer token with your API key. ### Response #### Success Response (200) - **batch_id** (string) - The unique identifier for the batch payout. - **status** (string) - The current status of the batch payout. - **created_at** (string) - Timestamp when the batch payout was created. - **payouts** (array) - A list of individual payout objects within the batch. - Each payout object contains: `payout_id`, `status`, `amount`, `currency`, `recipient_name`, `recipient_mobile`. #### Response Example ```json { "batch_id": "bp_abcdef12345", "status": "completed", "created_at": "2023-10-27T12:00:00Z", "payouts": [ { "payout_id": "po_12345abcde", "status": "completed", "amount": "500", "currency": "XOF", "recipient_name": "Fatou Ndiaye", "recipient_mobile": "+221555110219" }, { "payout_id": "po_67890fghij", "status": "failed", "amount": "1000", "currency": "XOF", "recipient_name": "Moussa Traore", "recipient_mobile": "+221555987654" } ] } ``` ``` -------------------------------- ### Payout API Payout Object Errors Source: https://docs.wave.com/payout/index Example of an error structure nested within a Payout object, demonstrating scenarios like a recipient exceeding their monthly limits. ```json { "id": "pt-185sw98jg1016", "currency": "XOF", "receive_amount": "16000", "fee": "160", "mobile": "+221555144081", "name": "Mame Diop", "status": "failed", "payout_error": { "error_code": "recipient-limit-exceeded", "error_message": "The recipient has reached their monthly limit." }, "timestamp": "2022-06-21T10:25:46Z" } ``` -------------------------------- ### GET /v1/payout-batch/:id Source: https://docs.wave.com/payout/index Retrieves a specific payout batch using its ID. ```APIDOC ## GET /v1/payout-batch/:id ### Description Retrieves a payout batch. ### Method GET ### Endpoint /v1/payout-batch/:id #### Path Parameters - **id** (string) - Required - The ID of the payout batch to retrieve. ### Request Example ``` curl -X GET \ --url https://api.wave.com/v1/payout-batch/pb-185skxq8g1006 \ -H 'Authorization: Bearer wave_sn_prod_YhUNb9d...i4bA6' ``` ### Response #### Success Response (200) - **id** (String) - The ID of the payout batch. - **status** (String) - The status of the payout batch: `processing` or `complete`. - **payouts** (List of payout results) - The list of payouts, with each item having the same structure as a single retrieved payout. - **id** (String) - The ID of the individual payout. - **currency** (String) - The currency of the payout. - **receive_amount** (String) - The amount received. - **fee** (String) - The fee for the payout. - **mobile** (String) - The mobile number of the recipient. - **name** (String) - The name of the recipient. - **status** (String) - The status of the individual payout: `succeeded`, `processing`, or `failed`. - **timestamp** (String) - The timestamp of the payout. - **aggregated_merchant_id** (String) - Optional - The aggregated merchant ID. - **payout_error** (Object) - Optional - Contains error details if the payout failed. - **error_code** (String) - The error code. - **error_message** (String) - The error message. #### Response Example ```json { "id": "pb-185skxq8g1006", "status": "complete", "payouts": [ { "id": "pt-185skxq9g100w", "currency": "XOF", "receive_amount": "1000", "fee": "10", "mobile": "+221555110219", "name": "Fatou Ndiaye", "status": "succeeded", "timestamp": "2022-06-21T10:07:30Z" }, { "id": "pt-185skxqa0100y", "currency": "XOF", "receive_amount": "1200", "fee": "10", "mobile": "+221555110233", "name": "Moustapha Mbaye", "status": "processing", "aggregated_merchant_id": "am-7lks22ap113t4", "timestamp": "2022-06-21T10:07:30Z" }, { "id": "pt-185sw98jg1016", "currency": "XOF", "receive_amount": "16000", "fee": "160", "mobile": "+221555144081", "name": "Mame Diop", "status": "failed", "payout_error": { "error_code": "recipient-limit-exceeded", "error_message": "The recipient has reached their monthly limit." }, "timestamp": "2022-06-21T10:25:46Z" } ] } ``` ### Note There is no `success` or `failed` status on payout batches, because within the same batch, various individual payouts can succeed or fail. In order to handle errors, each payout in `payouts` should be inspected to check if it contains a `payout_error` field. ``` -------------------------------- ### GET /v1/payout/:id Source: https://docs.wave.com/payout/index Retrieve details of a specific payout using its unique identifier. ```APIDOC ## GET /v1/payout/:id ### Description Retrieve details of a specific payout using its unique identifier. ### Method GET ### Endpoint https://api.wave.com/v1/payout/:id ### Parameters #### Path Parameters - **id** (string) - Required - The unique identifier of the payout. #### Header Parameters - **Authorization** (string) - Required - Bearer token with your API key. ### Response #### Success Response (200) - **payout_id** (string) - The unique identifier for the payout. - **status** (string) - The current status of the payout. - **amount** (string) - The amount of the payout. - **currency** (string) - The currency of the payout. - **recipient_name** (string) - The name of the recipient. - **recipient_mobile** (string) - The mobile number of the recipient. - **created_at** (string) - Timestamp when the payout was created. #### Response Example ```json { "payout_id": "po_12345abcde", "status": "completed", "amount": "500", "currency": "XOF", "recipient_name": "Fatou Ndiaye", "recipient_mobile": "+221555110219", "created_at": "2023-10-27T10:00:00Z" } ``` ``` -------------------------------- ### Common Payout API Request Errors Source: https://docs.wave.com/payout/index Examples of common errors returned by the Payout API, including validation errors for requests and general message errors. These JSON structures illustrate typical error formats. ```json { "error": "request-validation-error", "message": "Invalid phone number." } ``` ```json { "code": "request-validation-error", "message": "Request invalid", "details": [ { "loc": ["currency"], "msg": "Unknown currency identifier: ABC. We require the currency to be a three-letter ISO 4217 code.", "type": "value_error" } ] } ``` -------------------------------- ### GET /v1/payout Source: https://docs.wave.com/payout/index_payout-api Retrieve the status of a specific payout using its unique identifier. This endpoint is essential for tracking the lifecycle of a payout and understanding its success or failure. ```APIDOC ## GET /v1/payout ### Description Retrieves the status of a payout. Once a payout is created, it initially has a `processing` status. This endpoint allows you to check if the payout has `succeeded` or `failed`. If a payout failed, the response will include a `payout_error` field detailing the reason for the failure. If a payout could not be entered into the system correctly, querying with its ID will result in a `not-found` error. ### Method GET ### Endpoint `/v1/payout` ### Parameters #### Query Parameters - **id** (string) - Required - The unique identifier of the payout. ### Response #### Success Response (200) - **id** (string) - The unique identifier of the payout. - **status** (string) - The current status of the payout (e.g., `processing`, `succeeded`, `failed`). - **payout_error** (string, optional) - If the status is `failed`, this field contains the reason for the failure. #### Response Example ```json { "id": "po_123abc", "status": "succeeded" } ``` #### Error Response Example (404 Not Found) ```json { "error": "not-found" } ``` ``` -------------------------------- ### Payout Error Object Example Source: https://docs.wave.com/payout/index This object represents an error that can occur during a payout process. It can be returned at the top-level for validation failures or within a specific payout for execution errors. The error_code is crucial for programmatic error handling, while error_message provides a human-readable explanation. ```json { "error_code": "insufficient-funds", "error_message": "Insufficient funds in wallet." } ``` -------------------------------- ### Search Payouts by Client Reference Source: https://docs.wave.com/payout/index Retrieves a list of payouts based on the provided client reference. This is useful for verifying specific payout transactions. The API requires an authorization token. ```curl curl -X GET \ --url https://api.wave.com/v1/payouts/search?client_reference=FAH.4827.1734 \ -H 'Authorization : Bearer wave_sn_prod_YhUNb9d...i4bA6' ``` -------------------------------- ### Create Payout Batch Source: https://docs.wave.com/payout/index Submits a payout batch containing one or multiple payouts for asynchronous processing. An idempotency key is required for safe retries. The response provides a batch ID for tracking. ```curl curl -X POST \ --url https://api.wave.com/v1/payout-batch \ -H "authorization: Bearer wave_sn_prod_YhUNb9d...i4bA6" \ -H 'content-type: application/json' \ -H 'idempotency-key: 65f735b4-b44b-429d-b0a8-550701e2393a' \ -d '{"payouts": [ { "currency": "XOF", "receive_amount": "1000", "name": "Fatou Ndiaye", "mobile": "+221555110219" }, { "currency": "XOF", "receive_amount": "1200", "name": "Moustapha Mbaye", "mobile": "+221555110233", "aggregated_merchant_id": "am-7lks22ap113t4", }, { "currency": "XOF", "receive_amount": "16000", "name": "Mame Diop", "mobile": "+221555144081" } ]}' ``` -------------------------------- ### POST /v1/payout-batch Source: https://docs.wave.com/payout/index Submits a payout batch, with one or multiple payouts to be executed. The processing of these transactions is asynchronous. ```APIDOC ## POST /v1/payout-batch ### Description Submits a payout batch, with one or multiple payouts to be executed. The processing of these transactions is asynchronous, meaning that this endpoint will not immediately return the resulting payouts. Instead, you receive an ID that you can then use to retrieve the payout batch result. ### Method POST ### Endpoint /v1/payout-batch #### Request Body - **payouts** (List of payout requests) - Required - The list of payouts to be sent. Each item should have the same structure used for a single payout request. - **currency** (string) - Required - The currency of the payout. - **receive_amount** (string) - Required - The amount to be received. - **name** (string) - Required - The name of the recipient. - **mobile** (string) - Required - The mobile number of the recipient. - **aggregated_merchant_id** (string) - Optional - The aggregated merchant ID. ### Request Example ```json { "payouts": [ { "currency": "XOF", "receive_amount": "1000", "name": "Fatou Ndiaye", "mobile": "+221555110219" }, { "currency": "XOF", "receive_amount": "1200", "name": "Moustapha Mbaye", "mobile": "+221555110233", "aggregated_merchant_id": "am-7lks22ap113t4" }, { "currency": "XOF", "receive_amount": "16000", "name": "Mame Diop", "mobile": "+221555144081" } ] } ``` ### Response #### Success Response (200) - **id** (String) - The ID of the payout batch that you can use to poll the get payout batch endpoint. #### Response Example ```json { "id": "pb-185skxq8g1006" } ``` ``` -------------------------------- ### GET /v1/payout/:id Source: https://docs.wave.com/payout/index Retrieves the details of a specific payout using its unique identifier. This is useful for checking the status and details of a previously initiated payout. ```APIDOC ## GET /v1/payout/:id ### Description Retrieves the details of a specific payout using its unique identifier. This is useful for checking the status and details of a previously initiated payout. ### Method GET ### Endpoint /v1/payout/:id ### Parameters #### Path Parameters - **id** (String) - Required - The unique identifier for the payout object (e.g., `pt-185sewgm8100t`). ### Request Body This endpoint does not accept a request body. ### Response #### Success Response (200) - **id** (String) - A unique identifier for the payout object. - **currency** (Currency code) - The amount currency. - **receive_amount** (Amount) - The amount to be paid out to the recipient, net of fees. - **fee** (Amount) - The fee for sending the payout. - **mobile** (Phone number) - The recipient mobile phone number. - **name** (String) - The recipient name. - **national_id** (String) - The recipient's national ID. - **client_reference** (String) - A unique string that you provide. - **payment_reason** (String) - An optional message with a payment reason. - **status** (Payout state) - The status of the payout: `processing`, `failed`, or `succeeded`. - **timestamp** (Timestamp) - The time and date that this payout request was recorded. - **aggregated_merchant_id** (String) - The aggregated merchant ID used for this payout. #### Response Example ```json { "id": "pt-185sewgm8100t", "currency": "XOF", "receive_amount": "15000", "fee": "150", "mobile": "+221555110233", "name": "Moustapha Mbaye", "national_id": "1751197904376", "client_reference": "FAH.4827.1734", "payment_reason": "Salary November 2022", "status": "succeeded", "timestamp": "2022-06-21T09:56:29Z", "aggregated_merchant_id": "am-7lks22ap113t4" } ``` ``` -------------------------------- ### Create Payout Batch Source: https://docs.wave.com/payout/index_payout-api Submits a payout batch containing one or multiple payouts. This is an asynchronous operation; an ID is returned to retrieve the batch status later. Requires an API key and an idempotency key for request uniqueness. ```curl curl -X POST \ --url https://api.wave.com/v1/payout-batch \ -H "authorization: Bearer wave_sn_prod_YhUNb9d...i4bA6" \ -H 'content-type: application/json' \ -H 'idempotency-key: 65f735b4-b44b-429d-b0a8-550701e2393a' \ -d '{"payouts": [ { "currency": "XOF", "receive_amount": "1000", "name": "Fatou Ndiaye", "mobile": "+221555110219" }, { "currency": "XOF", "receive_amount": "1200", "name": "Moustapha Mbaye", "mobile": "+221555110233", "aggregated_merchant_id": "am-7lks22ap113t4", }, { "currency": "XOF", "receive_amount": "16000", "name": "Mame Diop", "mobile": "+221555144081" } ]}' ``` ```shell curl -X POST \ --url https://api.wave.com/v1/payout-batch \ -H "authorization: Bearer wave_sn_prod_YhUNb9d...i4bA6" \ -H 'content-type: application/json' \ -H 'idempotency-key: 65f735b4-b44b-429d-b0a8-550701e2393a' \ -d '{"payouts": [ { "currency": "XOF", "receive_amount": "1000", "name": "Fatou Ndiaye", "mobile": "+221555110219" }, { "currency": "XOF", "receive_amount": "1200", "name": "Moustapha Mbaye", "mobile": "+221555110233", "aggregated_merchant_id": "am-7lks22ap113t4", }, { "currency": "XOF", "receive_amount": "16000", "name": "Mame Diop", "mobile": "+221555144081" } ]}' ``` ```php "XOF", "receive_amount" => "1000", "name" => "Fatou Ndiaye", "mobile" => "+221555110219"], ["currency" => "XOF", "receive_amount" => "1200", "name" => "Moustapha Mbaye", "mobile" => "+221555110233", "aggregated_merchant_id" => "am-7lks22ap113t4"], ["currency" => "XOF", "receive_amount" => "16000", "name" => "Mame Diop", "mobile" => "+221555144081"] ]; curl_setopt($curl, CURLOPT_URL, 'https://api.wave.com/v1/payout-batch'); curl_setopt($curl, CURLOPT_RETURNTRANSFER, true); curl_setopt($curl, CURLOPT_POST, true); curl_setopt($curl, CURLOPT_POSTFIELDS, json_encode(['payouts' => $payouts])); curl_setopt($curl, CURLOPT_HTTPHEADER, [ 'Authorization: Bearer wave_sn_prod_YhUNb9d...i4bA6', 'Content-Type: application/json', 'Idempotency-Key: 65f735b4-b44b-429d-b0a8-550701e2393a' ]); $response = curl_exec($curl); if (curl_errno($curl)) { echo 'Error:' . curl_error($curl); } courl_close($curl); var_dump(json_decode($response)); ?> ``` ```javascript const payoutBatch = { payouts: [ { "currency": "XOF", "receive_amount": "1000", "name": "Fatou Ndiaye", "mobile": "+221555110219" }, { "currency": "XOF", "receive_amount": "1200", "name": "Moustapha Mbaye", "mobile": "+221555110233", "aggregated_merchant_id": "am-7lks22ap113t4" }, { "currency": "XOF", "receive_amount": "16000", "name": "Mame Diop", "mobile": "+221555144081" } ] }; fetch('https://api.wave.com/v1/payout-batch', { method: 'POST', headers: { 'Authorization': 'Bearer wave_sn_prod_YhUNb9d...i4bA6', 'Content-Type': 'application/json', 'Idempotency-Key': '65f735b4-b44b-429d-b0a8-550701e2393a' }, body: JSON.stringify(payoutBatch) }) .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error('Error:', error)); ``` ```java import java.net.URI; import java.net.http.HttpClient; import java.net.http.HttpRequest; import java.net.http.HttpResponse; import java.io.IOException; public class CreatePayoutBatch { public static void main(String[] args) throws IOException, InterruptedException { HttpClient client = HttpClient.newHttpClient(); String requestBody = "{\"payouts\": [ {\"currency\": \"XOF\", \"receive_amount\": \"1000\", \"name\": \"Fatou Ndiaye\", \"mobile\": \"+221555110219\"}, {\"currency\": \"XOF\", \"receive_amount\": \"1200\", \"name\": \"Moustapha Mbaye\", \"mobile\": \"+221555110233\", \"aggregated_merchant_id\": \"am-7lks22ap113t4\"}, {\"currency\": \"XOF\", \"receive_amount\": \"16000\", \"name\": \"Mame Diop\", \"mobile\": \"+221555144081\"} ]}"; HttpRequest request = HttpRequest.newBuilder() .uri(URI.create("https://api.wave.com/v1/payout-batch")) .header("Authorization", "Bearer wave_sn_prod_YhUNb9d...i4bA6") .header("Content-Type", "application/json") .header("Idempotency-Key", "65f735b4-b44b-429d-b0a8-550701e2393a") .POST(HttpRequest.BodyPublishers.ofString(requestBody)) .build(); HttpResponse response = client.send(request, HttpResponse.BodyHandlers.ofString()); System.out.println(response.body()); } } ``` ```python import requests url = "https://api.wave.com/v1/payout-batch" payload = { "payouts": [ { "currency": "XOF", "receive_amount": "1000", "name": "Fatou Ndiaye", "mobile": "+221555110219" }, { "currency": "XOF", "receive_amount": "1200", "name": "Moustapha Mbaye", "mobile": "+221555110233", "aggregated_merchant_id": "am-7lks22ap113t4" }, { "currency": "XOF", "receive_amount": "16000", "name": "Mame Diop", "mobile": "+221555144081" } ] } headers = { "Authorization": "Bearer wave_sn_prod_YhUNb9d...i4bA6", "Content-Type": "application/json", "Idempotency-Key": "65f735b4-b44b-429d-b0a8-550701e2393a" } response = requests.post(url, json=payload, headers=headers) print(response.json()) ``` -------------------------------- ### POST /v1/payout-batch Source: https://docs.wave.com/payout/index Initiate a batch payout, sending money to multiple recipients in a single request. ```APIDOC ## POST /v1/payout-batch ### Description Initiate a batch payout, sending money to multiple recipients in a single request. ### Method POST ### Endpoint https://api.wave.com/v1/payout-batch ### Parameters #### Header Parameters - **Authorization** (string) - Required - Bearer token with your API key. - **Content-Type** (string) - Required - `application/json` - **Idempotency-Key** (string) - Required - A unique key to ensure safe retries without accidental duplicate transactions. #### Request Body - **currency** (string) - Required - The currency code for the payout. - **recipients** (array) - Required - A list of recipient objects. - Each recipient object contains: - **receive_amount** (string) - Required - The amount to be received by the recipient. - **name** (string) - Required - The full name of the recipient. - **mobile** (string) - Required - The mobile number of the recipient, including country code. ### Request Example ```json { "currency": "XOF", "recipients": [ { "receive_amount": "500", "name": "Fatou Ndiaye", "mobile": "+221555110219" }, { "receive_amount": "1000", "name": "Moussa Traore", "mobile": "+221555987654" } ] } ``` ### Response #### Success Response (200) - **batch_id** (string) - The unique identifier for the batch payout. - **status** (string) - The status of the batch payout operation. - **payout_ids** (array) - A list of payout IDs included in the batch. #### Response Example ```json { "batch_id": "bp_abcdef12345", "status": "processing", "payout_ids": ["po_12345abcde", "po_67890fghij"] } ``` ``` -------------------------------- ### Payout Error Structure Source: https://docs.wave.com/payout/index_payout-api An example of the payout error object returned by the API. This object contains an error code and an optional error message, used for handling specific payout failures. ```json { "error_code": "insufficient-funds", "error_message": "Insufficient funds in wallet." } ``` -------------------------------- ### Generate Idempotency Key (Python) Source: https://docs.wave.com/payout/index_payout-api Generates a v4 UUID string in Python, which is a recommended format for idempotency keys. This ensures uniqueness for API requests and supports safe retries. ```python import uuid idem_key = str(uuid.uuid4()) ``` -------------------------------- ### API Request Validation Error Example Source: https://docs.wave.com/payout/index_payout-api This snippet demonstrates a common error returned when the API receives a request with an invalid phone number. It highlights the 'request-validation-error' code and a specific message detailing the issue. ```json { "error": "request-validation-error", "message": "Invalid phone number." } ``` -------------------------------- ### Retrieve Payout by ID using cURL Source: https://docs.wave.com/payout/index Shows how to retrieve a specific payout's details using the Wave API via a cURL command. This includes the endpoint, HTTP method, and necessary authorization header. ```shell curl -X GET \ --url https://api.wave.com/v1/payout/pt-185sewgm8100t \ -H 'Authorization: Bearer wave_sn_prod_YhUNb9d...i4bA6' ``` -------------------------------- ### Generate Idempotency Key (PHP) Source: https://docs.wave.com/payout/index_payout-api Generates a unique, entropy-rich string in PHP for use as an idempotency key. This helps prevent accidental duplicate transactions when making API calls. ```php $idem_key = uniqid(more_entropy: True) ``` -------------------------------- ### Generate Idempotency Key (openssl) Source: https://docs.wave.com/payout/index_payout-api Generates a random hexadecimal string suitable for use as an idempotency key using the openssl command-line tool. This is useful for ensuring safe retries of API requests. ```shell openssl rand -hex 8 ``` -------------------------------- ### Data Types Source: https://docs.wave.com/payout/index Defines the standard data types used within the Wave Payout API. ```APIDOC ## Data Types ### Amount All amounts are represented as a string. The amount must be a whole number (no decimal places). **Rules:** * No leading zeros if the value is one or greater. * Must be positive for requests. ### Currency Code Standard ISO 4217 three-letter codes in upper case are used. * Example: `USD`, `EUR` * Note: The code for the West African Franc is `XOF`, not `CFA`. ### Phone Number Phone numbers follow the E.164 standard. They must include a country code preceded by `+`. * Example: `+12345678901` ### Timestamp An ISO 8601 date and time format. * Time zone: UTC * Precision: Seconds * Format: `YYYY-MM-DDThh:mm:ssZ` * Example: `2022-06-20T17:17:11Z` ``` -------------------------------- ### Payout Batch State Enum Source: https://docs.wave.com/payout/index Enumeration of possible states for a payout batch. ```APIDOC ## Payout Batch State ### Description A payout batch state is represented as a string that matches exactly one of the following values. ### Enum Values * **processing** The payout request has been submitted and is in the process of being executed. * **complete** All the payouts in the batch have been processed. Individual payouts might have succeeded or failed; this needs to be checked on each payout within the batch. ``` -------------------------------- ### Name Verification Endpoint Rate Limiting Source: https://docs.wave.com/payout/index Information regarding the rate limits for the name verification endpoint. ```APIDOC ## Rate Limiting - Name Verification ### Description Details the rate limits and penalties for the name verification endpoint (`/v1/user_name_matches/`). ### Limits * **Limit:** Up to **30 checks** for the **same phone number** in any **5-minute** window. * **Penalty:** If the limit is exceeded for the same phone number, that phone number will be **blocked for 60 minutes** for further name-checks. ### Notes * This rate limit applies **only** to the name verification endpoint and **does not** affect remittance or payout posting endpoints. * The `recipient-not-verified` error is no longer raised and can be disregarded. ``` -------------------------------- ### Retrying Transactions Source: https://docs.wave.com/payout/index Guidance on implementing retry logic for transactions, distinguishing between system errors, rate limiting, and validation errors. ```APIDOC ## Retrying transactions ### Description The following are Wave's recommendations on retry logic. Please carefully read the section on Errors and Idempotency. ### System errors Some errors are unexpected, which means the transaction is in an **unknown state**. This can for example happen during an outage or when there are internet connectivity issues. * It is important that you mark your transactions internally as being **pending**. * You should then retry those transactions using the same idempotency key. There is no time limit for retrying. * Use retries that start at 1-second intervals and then use exponential backoff. * If you have an payout ID or a `client_reference`, then you can also fetch the payout to inspect its state * The following are the error codes where this can occur: * `408` Request Timeout * `500` Internal Server Error. * `503` Service Unavailable. The server is unable to handle the request due to a temporary overload or scheduled maintenance. Try again later. * `5xx`: You should retry on all internal server errors. ### Rate limiting errors Rate limiting errors of type "`429` Too Many Requests" should always be retried. Of course you should wait a few seconds before retrying. You should still mark them internally as **pending** instead of failed. ### Validation and balance errors All other errors are final, so your system can mark the transaction as **failed**. * Example 1: if the recipient has reached an account limit, it doesn't make sense to immediately retry. * Example 2: if the request was invalid because a field was missing, there is no sense in retrying. To summarize: You should generally retry on unexpected errors like connection problems and unavailable services. Always use the same idempotency key when retrying a payout or batch. ``` -------------------------------- ### Generate Idempotency Key (JavaScript) Source: https://docs.wave.com/payout/index_payout-api Generates a v4 UUID string in JavaScript using the built-in crypto API. This is a standard method for creating unique idempotency keys for API requests. ```javascript let idem_key = crypto.randomUUID(); ``` -------------------------------- ### POST /v1/payout Source: https://docs.wave.com/payout/index_payout-api Creates a new payout. This endpoint initiates the process of transferring funds to a recipient. In cases of system errors (5xx), a payout might still be created without returning an ID, requiring a retry with the same idempotency key. ```APIDOC ## POST /v1/payout ### Description Initiates a new payout. When an error occurs during payout creation, especially 5xx errors due to system outages, the payout might still be processed internally without returning an ID. In such extraordinary cases, it is safe to retry the payout using the same idempotency key. ### Method POST ### Endpoint `/v1/payout` ### Parameters #### Request Body - **amount** (object) - Required - The amount to be paid out. - **currency** (string) - Required - The currency of the amount (e.g., 'CAD', 'USD'). - **value** (integer) - Required - The amount in the smallest currency unit (e.g., cents for USD). - **recipient** (object) - Required - Details of the payout recipient. - **destination** (string) - Required - The destination for the payout (e.g., bank account or email). - **name** (string) - Required - The full name of the recipient. - **idempotency_key** (string) - Required - A unique key to ensure the request is processed only once. ### Request Example ```json { "amount": { "currency": "CAD", "value": 10000 }, "recipient": { "destination": "bank:routing_number=123456789;account_number=987654321", "name": "Jane Doe" }, "idempotency_key": "a1b2c3d4e5f6" } ``` ### Response #### Success Response (201 Created) - **id** (string) - The unique identifier of the created payout. #### Response Example ```json { "id": "po_123abc" } ``` ```