Balance & Reconciliation API
The Balance API provides a programmatic means to retrieve the balance and list all the transactions processed by your Wave Business Wallet. With this API you will be able to easily do automated daily reconciliation, setup balance alerts, issue refunds and more.
For real time notifications about the payments received by your account, you should not use this API, but Webhooks.
ENDPOINTS:
GET /v1/balance
GET /v1/transactions
POST /v1/transactions/:transaction_id/refund
Base URL
All the endpoint paths referenced in the API document are relative to a base URL, https://api.wave.com.
Authentication
Authenticating to the API is done via API keys. These keys are bound to a single business wallet and can only interact with it.
If you need to interact with more than one wallet in your network, then you will have to obtain one key per wallet.
Each request must be sent over HTTPS and contain an authorization header specifying the bearer scheme with the api key:
Authorization: Bearer wave_sn_prod_YhUNb9d...i4bA6
Note that the actual key is much longer but for documentation purposes most of the characters have been replaced by an ellipses.
Obtaining your API key
You can manage API keys in the developer's section in the Wave Business Portal. You can create, view, and revoke keys, and define which specific APIs each key has access to.
When you create a new API key, you will only see the full key once. Make sure you copy it without missing any characters, since it will be masked afterwards for security reasons.
Wave doesn't know your full key, but if you contact API support we can identify them by the last 4 letters that you see displayed in the business portal.
Error codes
In the authentication phase, one of the following errors can cause your request to return early:
Status | Code | Descriptions |
---|---|---|
401 | missing-auth-header |
Your request should include an HTTP auth header. |
401 | invalid-auth |
Your HTTP auth header can't be processed. |
401 | api-key-not-provided |
Your request should include an API key. |
401 | no-matching-api-key |
The key you provided doesn't exist in our system. |
401 | api-key-revoked |
Your API key has been revoked. |
403 | invalid-wallet |
Your wallet can't be used in this particular API. |
403 | disabled-wallet |
Your wallet has been temporarily disabled. You should still be able to use the endpoint to check your balance. |
Types
Some of the parameters in Wave API requests or attributes in API objects follow specific data formats.
Amounts
All amounts are represented as strings. When the amount includes decimal places, the separator is a period (.
). The following rules apply to valid amounts:
- Include between zero and two decimal places. (See Currency for the maximum number of allowed decimal places for each currency.)
- No leading zeroes where the value is one or greater.
- One leading zero where the value is less than one.
- May include trailing zeroes.
- Must be positive for requests. May be zero or negative in object attributes.
Currency
Standard ISO 4217 three-letter codes in upper case are used to specify currency.
The code for the West African Franc is XOF
. Decimal places are not allowed for XOF currency amounts.
Timestamps
Timestamp values follow the ISO 8601 standard. Timestamps that we provide in API objects will be of the form YYYY-MM-DDThh:mm:ssZ
where the Z
indicates the UTC time zone.
Transaction Type
Name | Description |
---|---|
merchant_payment |
A payment from a customer to a business. |
merchant_payment_refund |
A refund of a merchant payment. |
api_checkout |
A payment from a customer to a business made through the Checkout API |
api_checkout_refund |
A refund of a checkout payment. |
api_payout |
A payment from a business to a customer, made through the Payout API |
api_payout_reversal |
A reversal of a business payment. |
bulk_payment |
A payment from a business to a customer, made through the Bulk Payments portal. |
bulk_payment_reversal |
A reversal of a business payment. |
b2b_payment |
A payment from a business to another business. |
b2b_payment_reversal |
A reversal of payment from a business to another business. |
merchant_sweep |
A reversal of payment from a business to another business. |
The Balance object
BALANCE OBJECT
{
"amount": "10245",
"currency": "XOF"
}
The Balance object represents the amount of money in a Wave wallet.
Attributes
amount string
Balance amount.
currency currency
Three-letter ISO 4217 currency code.
API
Retrieve balance
GET /v1/balance
Retrieves the current balance of the account associated with the API key used to make the request.
curl \
-H 'Authorization: Bearer wave_sn_prod_YhUNb9d...i4bA6' \
https://api.wave.com/v1/balance
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.wave.com/v1/balance",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer wave_sn_prod_YhUNb9d...i4bA6"
],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
const axios = require('axios');
axios.get('https://api.wave.com/v1/balance', {
headers: {
'Authorization': 'Bearer wave_sn_prod_YhUNb9d...i4bA6'
}
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
HttpResponse<String> response = Unirest.get("https://api.wave.com/v1/balance")
.header("Authorization", "Bearer wave_sn_prod_YhUNb9d...i4bA6")
.asString();
System.out.println(response.getBody());
Parameters
URL parameters are passed in the form of https://api.wave.com/v1/balance?include_subaccounts=true
.
Name | Type | Description |
---|---|---|
include_subaccounts |
URL parameter (optional) | If your account has readable subaccounts (like an HQ account with supervisors or cashiers under them, then include their balance in the total. |
Returns
Returns a balance object for the account associated with the API key used to make the request.
Retrieve your transactions
GET /v1/transactions
Returns a list of transactions of your account for a given day. Uses pagination if the number of transactions exceeds 1000 entries. The transactions are ordered from older to newer.
curl -X GET \
--url https://api.wave.com/v1/transactions?date=2022-10-25 \
-H 'Authorization: Bearer wave_sn_prod_YhUNb9d...i4bA6'
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.wave.com/v1/transactions?date=2022-10-25",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "GET",
CURLOPT_HTTPHEADER => [
"Authorization: Bearer wave_sn_prod_YhUNb9d...i4bA6"
],
]);
$response = curl_exec($curl);
curl_close($curl);
echo $response;
const axios = require('axios');
axios.get('https://api.wave.com/v1/transactions?date=2022-10-25', {
headers: {
'Authorization': 'Bearer wave_sn_prod_YhUNb9d...i4bA6'
}
})
.then(response => {
console.log(response.data);
})
.catch(error => {
console.error(error);
});
HttpResponse<String> response = Unirest.get("https://api.wave.com/v1/transactions?date=2022-10-25")
.header("Authorization", "Bearer wave_sn_prod_YhUNb9d...i4bA6")
.asString();
System.out.println(response.getBody());
Example response
{
"page_info": {
"start_cursor": null,
"end_cursor": "TFRfdUZ1MGoyMzVKemtz",
"has_next_page": true
},
"date": "2022-11-07",
"items": [
{
"timestamp": "2022-11-07T14:41:15Z",
"transaction_id": "T_V3TFOUE7VU",
"amount": "99",
"fee": "1",
"currency": "XOF",
"counterparty_name": "Mame Diop",
"counterparty_mobile": "+221761110000"
},
{
"timestamp": "2022-11-07T14:42:06Z",
"transaction_id": "T_2YJNPWMCIY",
"amount": "99",
"fee": "1",
"currency": "XOF",
"counterparty_name": "Fatou Ndiaye",
"counterparty_mobile": "+221761110001"
},
{
"timestamp": "2022-11-07T14:42:41Z",
"transaction_id": "T_2YJNPWMCIY",
"amount": "-99",
"fee": "-1",
"currency": "XOF",
"is_reversal": true
},
{
"timestamp": "2022-11-07T14:42:54Z",
"transaction_id": "pt-1azcvz4081002",
"amount": "-101",
"fee": "1",
"currency": "XOF",
"counterparty_name": "Moustapha Mbaye",
"counterparty_mobile": "+221761110519"
},
{
"timestamp": "2022-11-07T14:43:00Z",
"transaction_id": "pt-1azcw0qkg1004",
"amount": "-121",
"fee": "1",
"currency": "XOF",
"counterparty_name": "Moustapha Mbaye",
"counterparty_mobile": "+221761110519"
},
{
"timestamp": "2022-11-07T14:43:14Z",
"transaction_id": "pt-1azcw0qkg1004",
"amount": "121",
"fee": "1",
"currency": "XOF",
"counterparty_name": "Moustapha Mbaye",
"counterparty_mobile": "+221761110519",
"is_reversal": true
}
]
}
Request parameters
URL parameters are passed in the form of https://api.wave.com/v1/transactions?date=value1&after=value2
.
Name | Type | Description |
---|---|---|
date |
URL parameter (optional) | Which day to fetch transactions for. Returns the current day's transactions if not specified. |
after |
URL parameter (optional) | The pointer of the page to fetch. This is an opaque string, and generally you just pass it the end_cursor of the previous page, as returned in the page_info object. See pagination. |
include_subaccounts |
URL parameter (optional) | If your account has readable subaccounts (like an HQ account with supervisors or cashiers under them, then include their transactions as well. Defaults to False. Note: business reports in the business portal include all subaccount transactions by default. |
Return attributes
Key | Type | Description |
---|---|---|
timestamp |
Timestamp | The execution time and date of the transaction. |
transaction_id |
String | A unique identifier for a transaction. Up to 20 characters. |
transaction_type |
Transaction Type | The type of transaction.. Can be empty. |
amount |
String | The amount difference that this transaction had on your account. |
fee |
String | The fee for the transaction. |
balance |
String | The wallet's balance after this transaction was executed. |
currency |
Currency code | The 3-letter ISO 4217 currency code of the transaction amount. |
is_reversal |
Boolean (optional) | Marked true if this is a reversal or refund of a previous transaction. |
counterparty_name |
String (optional) | The name of the counterparty (sender or receiver) of the transaction. |
counterparty_mobile |
String (optional) | The mobile number of the counterparty (sender or receiver) of the transaction. |
counterparty_id |
String (optional) | The identifier of the counterparty in B2B payments. |
business_user_name |
String (optional) | The name of the business user involved in the transaction. This is for example the shop assistant/business user, or the depositor for an agent transaction. |
business_user_mobile |
String (optional) | The mobile number of the business user involved in the transaction. |
employee_id |
String (optional) | The employee ID associated with the busienss user involved in the transaction. |
client_reference |
String (optional) | A unique string that you (optionally) provided when submitting the transaction. |
payment_reason |
String (optional) | A payment reason or message that you (optionally) provided when submitting the transaction. |
checkout_api_session_id |
String (optional) | If this payment is linked to a Checkout API session, this is its ID. |
batch_id |
String (optional) | The batch ID if this transaction is part of a bulk payment. |
aggregated_merchant_id |
String (optional) | The ID of the aggregated merchant this transaction is assigned to. Only applicable if you're an aggregator processing payments for a merchant that is integrating via your services. |
aggregated_merchant_name |
String (optional) | The name of the aggregated merchant this transaction is assigned to. Only applicable if you're an aggregator processing payments for a merchant that is integrating via your services. |
custom_fields |
JSON Object (optional) | A key-value map of any custom fields related to this payment. |
submerchant_id |
String (optional) | If the transaction belongs to a sub-account, this field denotes the ID of the account that the transaction happened under. |
submerchant_name |
String (optional) | If the transaction belongs to a sub-account, this field denotes the name of the account that the transaction happened under. |
Refund a transaction
POST /v1/transactions/:transaction_id/refund
With this endpoint you can reverse a payment received, including fees. You don't need to indicate a reason, you can simply refund your customers any time you deem necessary.
curl -X POST \
-L https://api.wave.com/v1/transactions/T_VZSWJF5MMQ/refund \
-H 'Authorization: Bearer wave_sn_prod_YhUNb9d...i4bA6'
Example response
HTTP 200 OK
Request parameters
There are no parameters necessary in the request body. Note that the transaction_id
is passed in the request path.
Response body
There is no response body. The status code will inform you whether a refund was successful (200), or the transaction doesn't exist (404), or something else went wrong (500).
Pagination
Many of Wave's listing endpoints support pagination. If you are using a paginated endpoint, you must be prepared to accept paginated responses and continue making requests until no items remain or you have retrieved all of the data your application needs.
Paginated request
Paginated endpoints currently only support forward pagination. Backward pagination is not yet supported.
Example paginated request
curl -X GET \
--url 'https://api.wave.com/v1/paginated-endpoint?first=10&after=YzE6YW0tMWFrbjhkeWcwMTAwOA'
For pagination, you may use the following query parameters:
Parameter | Type | Description |
---|---|---|
first |
Integer (optional) | The maximum number of items to retrieve. The server may respond with fewer items if your limit is too high, or if there aren't enough items remaining to fulfill the request. |
after |
String (optional) | An opaque cursor indicating where pagination should continue from. Typically you will use the value of page_info.end_cursor from the previous response. |
Paginated response
Example paginated response
{
"page_info": {
"has_next_page": true,
"end_cursor": "YzE6YW0tMWFrbjhkeWcwMTAwOA"
},
"items": [
{
"id": "xyz-bm29dahzl",
"name": "Item 1"
}
]
}
A paginated response contains pagination information and a list of items. The specific item type is endpoint-dependent.
Key | Type | Description |
---|---|---|
page_info |
Page Info | Pagination information. |
items |
List of objects | A list of items. Item type varies by endpoint. |
Page Info object
The page info object contains information related to the current page of results, and a cursors that can be used to retrieve the next page.
Key | Type | Description |
---|---|---|
has_next_page |
Boolean | true if there is a next page after this one, false otherwise. |
end_cursor |
String | A cursor that can be used to fetch the next page of items. |
Example pagination request flow
Example initial request
curl -X GET \
--url 'https://api.wave.com/v1/paginated-endpoint?first=10' \
-H 'Authorization: Bearer wave_sn_prod_YhUNb9d...i4bA6'
Example initial response
{
"page_info": {
"has_next_page": true,
"end_cursor": "YzE6YW0tMWFrbjhkeWcwMTAwOA"
},
"items": [
...
]
}
As an example, we can retrieve items from an endpoint, ten items at a time.
Note: The first
query parameter is optional if we don't care about the precise number of items being retrieved. The server will choose a sensible default for the collection being retrieved.
Example next-page request
curl -X GET \
--url 'https://api.wave.com/v1/paginated-endpoint?first=10&after=YzE6YW0tMWFrbjhkeWcwMTAwOA' \
-H 'Authorization: Bearer wave_sn_prod_YhUNb9d...i4bA6'
Example next-page response
{
"page_info": {
"has_next_page": false,
"end_cursor": "YzE6YW0tMWFrbjhkeWc6iNNoqP"
},
"items": [
...
]
}
When the response's page_info.has_next_page
is true
, more items remain to be retrieved. We can request another page of items using the page_info.end_cursor
as our after
query parameter.
Because this response has returned page_info.has_next_page
as false
, no items remain to be retrieved, and no further requests should be made. However, if page_info.has_next_page
had been true
, we could have again used the value of page_info.end_cursor
as the value of our after
query parameter to continue retrieving items.
Changelog
2024-03-29
Removes override_business_name
details from the Checkout API
2022-10-17
Added aggregated_merchant_id
details to the Checkout API.
2022-05-10
The Checkout API now validates decimal places following the rules described in the Amount section.
2022-03-29
Adds override_business_name
details to Checkout API
2022-03-23
Initial release of Checkout and Balance APIs.