Overview
ZENGAPAY is a Payments Gateway that enables businesses to receive payments from their customers via mobile money, as well as make mobile money payments to any mobile money account holder or send Mobile Airtime or Mobile Voice & Data Bundles directly to users.
ZENGAPAY offers a rich API which enables seamless integration with applications, websites, mobile apps, SMS services and any other medium through which businesses interact with their customers.
Scroll down for examples.
About the ZENGAPAY API
This is the official ZENGAPAY API documentation.
The ZENGAPAY API operates over HTTPS
and uses JSON as its data format. The API is a RESTful API and utilizes HTTP methods
and HTTP status codes
to specify requests and responses.
We provide libraries for several languages, including PHP
, Java
, Ruby
and Python
. You can view code examples in the dark area to the right, and you can switch the programming language of the examples with the tabs in the top right.
All responses shall be returned using JSON, however, if you are using the language libraries, the JSON responses will be converted into native, language specific objects.
Supported Operations
The API provides support for both transaction-oriented operations and non transaction-oriented operations. A transaction-oriented operation is an operation intended to result in the transfer of funds from one account to another account.
Transaction-oriented Operations
The API supports the following transaction-oriented operations. Note that these operations are also available from the Web Interface.
Non Transaction-oriented Operations
The Following are the non transaction-oriented operations supported by the API:
- Check Transaction Status
- Check Account Balance
- Get Account Statement
- Get Supported Networks
- Get Supported Banks
- Manage Contacts
All the above operations are fully described in the later sections of this API Document.
Getting Started
We have production as well as test server environments. The test server environment is called sandbox.
You are advised to signup for a free account in sandbox, get your API Token by going to Settings → Developer Settings and test all your API calls on the sandbox environment before pointing your application to production.
To point an application to production, you need make only minor changes. In most cases, you simply need to change the API service URL
and API TOKEN
.
Sandbox Environment
The following is the API Endpoint for our sandbox environment:
Production Environment
We can't stress this enough: Please test your APIs against our sandbox environment before pointing them to production. We prefer to avoid service disruptions in production caused by untested code.
Here is the API Endpoint for our production environment:
Plugins And Libraries
As an alternative to working directly with our API you may also consider to use our:
- PHP Library - https://github.com/zengapay/zengapay-php
Python Library - https://github.com/zengapay/zengapay-python
WooCommerce Plugin - https://github.com/zengapay/zengapay-woocommerce
Request/Response Format
The default response format is JSON. Requests with a message-body use plain JSON to set or update resource attributes. Successful requests will return a 200 (OK)
, 201 (CREATED)
or a 202 (ACCEPTED)
HTTP status.
Some general information about responses:
- Dates are returned the format:
YYYY-MM-DD HH:mm:ss
- Any decimal monetary amount, such as prices or totals, will be returned as strings with two decimal places.
- Other amounts, such as item counts, are returned as
integers
. - Blank fields are generally included as
null
orempty
string instead of being omitted.
Rate Limiting
All requests, whether they are authenticated or not, are subject to rate limiting. If you have reached your limit, your requests will be handled with a 429 Too Many Requests
error. Burst requests are allowed. Responses contain several headers which provide information about your current rate limit status.
- The
RateLimit-Limit
header contains the total number of requests you can perform per minute. - The
RateLimit-Remaining
header contains the number of requests remaining in the current rate limit time frame.
Pagination
Responses which return multiple items support pagination. If they do support pagination, it can be controlled with following query string parameters:
- A
page
parameter specifies the page to fetch. The number of the first page is 1. - A
per_page
parameter specifies the number of items returned per page. The default value is 25, the maximum value is 50 except otherwise specified in the documentation.
Error Handling
ZENGAPAY uses HTTP response status codes to indicate success or failure. When a request to our API is successful, The ZENGAPAY API returns an HTTP response code in the 2XX range
. And when a request fails, returns an HTTP response code in the 4XX
or 5XX
range.
In summary:
- Codes in the
2XX
range mean that the request was processed successfully - Codes in the
4XX
range mean that something was wrong with the data that you sent. For example, you might have missed some required parameters, or you might be using a wrong API token. - Codes in the
5XX
range mean that something went wrong within ZENGAPAY's servers.
In all cases, the response will include an appropriate status code and content-type. The body of the response will include any additional details regarding the nature of the error.
Most error responses will include a message
key in the body of the response, but some may include additional information, for example, they may include information about missing fields.
The examples to the right show some of the errors that might occur, including the status code and content-type in the response header, and the json-formatted details in the response body.
401 Unauthorized error response due to using a wrong token.
{
"code": 401,
"status": "Unauthorized",
"message": "The API KEY you supplied is either INVALID or API access has been DISABLED because your account is unverified. If this error persists, please contact [email protected]"
}
Authentication
To authorize, use this code:
curl --header 'Authorization: Bearer <YOUR_API_TOKEN>' --location 'https://api.zengapay.com/v1/'
Make sure to replace YOUR_API_TOKEN with your API Token eg ZPYPUBK-x9cb6a2b822267b21ec4c5XXXXXXXXXXXXX
All requests to the ZENGAPAY API must be authenticated via a API token. Include your secret API token in every request you send to the API with the Authorization HTTP header.
Authorization: Bearer <YOUR_API_TOKEN>
To create a new API Token, Login into your ZENGAPAY Dashboard, go to Settings → Developer Settings, and create a new Key.
An Example of Authorization in Postman
IP Whitelisting
You should whitelist at least one IP before your API access will fully begin to work.
Only requests from whitelisted IP addresses will be allowed access to security sensitive actions such as Transfers, Airtime & Data Transfers.
IP Address(es) can be whitelisted in the following way:
Go to Settings → Developer Settings.
Scroll down to the IP Address(es) section.
Add one or more IP Address(es) separated by commas. eg
95.217.165.253,88.198.95.21
Proceed to Save Changes.
Please keep in mind that only IPv4 addresses can be used and the IP must be your SERVER's or ISP's Public IP.
Protected Endpoint that requires Whitelisted IPs
{
"code": 403,
"status": "Forbidden",
"message": "Connection refused from unauthorized IP: 81.202.241.36, This IP is NOT unauthorized to access the /account endpoint on your account. If you believe this is in error, please contact [email protected]"
}
Transaction Statuses
Transaction-oriented Operations such as collections, payouts and internal transfers will return one of these transaction statuses FAILED
, PENDING
,SUCCEEDED
or INDETERMINATE
.
The diagram below attempts to provide a visual explanation of the transaction statuses supported in the system.
FAILED - This means that your transaction was not successful. You may re-submit your request for processing if there was an error on your part.
PENDING - This means that your transaction has not yet been processed to a conclusion.
SUCCEEDED - This means that your transaction was Successful
INDETERMINATE - This means that your transaction is pending resolution. This normally happens if there was a delay in processing of mobile money transactions. Typically requests which result in this status are resolved within 24 hours of your initiating the request.
Receiving Funds
Introduction
ZENGAPAY uses the term Collections to refer to money that you receive (or collect) from a mobile subscriber. This differentiates money you receive (Collections) from money you send to mobile subscribers (Transfers).
Collections
Use this to deposit funds into your account by transferring the said funds from a mobile money account holder. An example of where this transaction is useful is when receiving payment from a mobile money user for services you are rendering to them.
Shortly after you submit your request, the mobile money user receives an on-screen notification on their mobile phone. This notification informs the mobile money user about your request to transfer funds out of their account, and requests them to authorize the request to complete the transaction. The transaction will not succeed unless the mobile money user authorizes it through the onscreen notification.
Related Webhooks
The collection.success
and collection.failed
events are triggered whenever something happens to a collection that you have initiated. For example, if it is successfully delivered or if it fails. You can configure a web link to receive notifications whenever this occurs. This will allow you to respond automatically whenever a collection is completed or whenever it fails.
See our Webhooks API documentation for more information.
Collections Endpoint
Sample Collection Request Object (JSON):
curl --location --request POST 'https://api.zengapay.com/v1/collections' \
--header 'Authorization: Bearer <YOUR_API_TOKEN>' \
--header 'Content-Type: application/json' \
--data-raw '{
"msisdn":"256775203801",
"amount":256600,
"external_reference":"400000",
"narration":"Credit Note - 11200390191",
"charge_customer":false}'
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.zengapay.com/v1/collections",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS =>"{\"msisdn\":\"256775203801\",\"amount\":256600,\"external_reference\":\"400000\",\"narration\":\"Credit Note - 11200390191\",\"charge_customer\":false"}",
CURLOPT_HTTPHEADER => array(
"Authorization: Bearer <YOUR_API_TOKEN>",
"Content-Type: application/json"
),
));
$response = curl_exec($curl);
print_r($response);
require "uri"
require "net/http"
url = URI("https://api.zengapay.com/v1/collections")
https = Net::HTTP.new(url.host, url.port);
https.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = "Bearer <YOUR_API_TOKEN>"
request["Content-Type"] = "application/json"
request.body = "{\"msisdn\":\"256775203801\",\"amount\":256600,\"external_reference\":\"400000\",\"narration\":\"Credit Note - 11200390191\"\n}"
response = https.request(request)
puts response.read_body
import requests
url = "https://api.zengapay.com/v1/collections"
payload = "{\"msisdn\":\"256775203801\",\"amount\":256600,\"external_reference\":\"400000\",\"narration\":\"Credit Note - 11200390191\"\n}"
headers = {
'Authorization': 'Bearer <YOUR_API_TOKEN>',
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data = payload)
print(response.text.encode('utf8'))
The Collection Request object
Request in Postman
Parameter | Type | Description |
---|---|---|
msisdn | Integer (Required) | The phone number that the collection request is intended for. Provide an internationally formatted number without the + . for example 256775203801 for MTN Uganda or 256755329361 for Airtel Uganda |
amount | Decimal (Required) | The collection request amount. eg 186600 or 186600.00 |
external_reference | String (Required) | Internal description or reason for this collection request and must be unique for every request. For example, this may be an invoice number or an internal transaction identifier in your system. eg 000000018889191 |
narration | String (Required) | Textual narrative describing the transaction. eg Clearing Invoice - #0000001889191 |
charge_customer | Boolean (Optional) | This indicates whether the customer should pay the transaction fees or not for this specific transaction. This can be true or false Also Under your merchant account settings, you can define whether we should charge you (the merchant) or the customer paying. |
The above command returns JSON structured like this:
{
"code": 202,
"status": "accepted",
"message": "Transaction Initiated",
"transactionReference": "48f4be7a-73b3-524d-9a98-6290b56c5f2e"
}
Response sample in Postman
Retrieving a single Collection (Checking Transaction Status)
To retrieve a single collection object (check status of a collection request), provide the transactionReference and a collection object will be returned.
Request Parameters
Parameter | Type | Description |
---|---|---|
transactionReference | UUID | The reference to the transaction whose status you would like to follow up on. This is typically the transaction reference which came through as part of an earlier collection request response. |
Sample Request:
curl --location --request GET 'https://api.zengapay.com/v1/collections/ab1df360-3191-5e8a-acd6-c65281f22e9f' \
--header 'Authorization: Bearer <YOUR_API_TOKEN>'
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.zengapay.com/v1/collections/ab1df360-3191-5e8a-acd6-c65281f22e9f",
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 => array(
"Authorization: Bearer <YOUR_API_TOKEN>"
),
));
$response = curl_exec($curl);
print_r($response);
require "uri"
require "net/http"
url = URI("https://api.zengapay.com/v1/collections/ab1df360-3191-5e8a-acd6-c65281f22e9f")
https = Net::HTTP.new(url.host, url.port);
https.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = "Bearer <YOUR_API_TOKEN>"
response = https.request(request)
puts response.read_body
import requests
url = "https://api.zengapay.com/v1/collections/ab1df360-3191-5e8a-acd6-c65281f22e9f"
payload = {}
headers = {
'Authorization': 'Bearer <YOUR_API_TOKEN>'
}
response = requests.request("GET", url, headers=headers, data = payload)
print(response.text.encode('utf8'))
Sample Response
The gateway will respond back with an object with this structure:
Response in displayed in Postman
Response Parameters
Parameter | Type | Description |
---|---|---|
transactionStatus | string | The status of the transaction, this can be one of these; PENDING ,SUCCEEDED ,FAILED ,INDETERMINATE |
transactionReference | string | The reference to the transaction requested |
MNOTransactionReferenceId | string | Mobile Network Operator (MNO) Transaction Reference Identifier. The value uniquely identifies this transaction on the relevant Mobile Network Operator's system. |
currencyCode | string | The currency code of the wallet currency in your merchant account where the amount paid by the customer will be deposited. |
msisdn | string | The mobile money account (phone) from where you are deducting the funds. |
amount | string | Amount requested for collection |
channel | string | The Channel through which the transaction was initiated. this can be one of these; API ,WEB ,APP |
transactionType | string | The transaction type. for collections this is usually INBOUND_MSISDN_CREDIT |
transactionInitiationDate | string | The transaction initiation date. This is of the format YYYY-MM-DD HH:mm:ss , e.g 2020-05-15 18:44:44 |
transactionCompletionDate | string | The transaction completion date. This is of the format YYYY-MM-DD HH:mm:ss , e.g 2020-05-15 18:44:55 . If the transaction is not yet complete, this will be set to 0000-00-00 00:00:00 |
Response:
{
"code": 200,
"status": "OK",
"data": {
"transactionSystemId": "ZPY210126134940TX",
"transactionReference": "4ff14e2a-27d5-5287-8783-46587e45f227",
"transactionStatus": "SUCCEEDED",
"amount": 176650,
"msisdn": "256755329361",
"channel": "API",
"customerCharged": false,
"currencyCode": "UGX-ATLMM",
"currencyName": "Ugandan shillings (Airtel Money)",
"MNOTransactionReferenceId": "49747002508",
"transactionExternalReference": "21012616232830",
"transactionExternalNarrative": "Clearing Invoice - 2101254558",
"transactionInitiationDate": "2021-01-26 16:23:38",
"transactionCompletionDate": "2021-01-26 16:23:56",
"transactionEntryGeneralType": "CREDIT",
"transactionEntryDesignation": "TRANSACTION",
"transactionEntrySpecificType": "INBOUND_MSISDN_CREDIT"
}
}
Retrieving all Collections
To retrieve a list of all collections, make a GET request to the collections endpoint. This will return a list of collection objects.
Response
{
"code": 200,
"status": "OK",
"collections": {
"current_page": 24,
"data": [
{
"transactionSystemId": "ZPY210125192181TX",
"transactionReference": "15ebb100-61fe-5a21-a3dd-990104284c11",
"transactionStatus": "SUCCEEDED",
"amount": 3000,
"msisdn": "256755329361",
"channel": "API",
"customerCharged": false,
"currencyCode": "UGX-ATLMM",
"currencyName": "Ugandan shillings (Airtel Money)",
"MNOTransactionReferenceId": "49724030274",
"transactionExternalReference": "21012522574267",
"transactionExternalNarrative": "Credit Note - 2101253783",
"transactionInitiationDate": "2021-01-25 22:57:42",
"transactionCompletionDate": "2021-01-25 22:57:52",
"transactionEntryGeneralType": "CREDIT",
"transactionEntryDesignation": "TRANSACTION",
"transactionEntrySpecificType": "INBOUND_MSISDN_CREDIT"
},
{
"transactionSystemId": "ZPY210126134940TX",
"transactionReference": "4ff14e2a-27d5-5287-8783-46587e45f227",
"transactionStatus": "SUCCEEDED",
"amount": 176650,
"msisdn": "256755329361",
"channel": "API",
"customerCharged": false,
"currencyCode": "UGX-ATLMM",
"currencyName": "Ugandan shillings (Airtel Money)",
"MNOTransactionReferenceId": "49747002508",
"transactionExternalReference": "21012616232830",
"transactionExternalNarrative": "Clearing Invoice - 2101254558",
"transactionInitiationDate": "2021-01-26 16:23:38",
"transactionCompletionDate": "2021-01-26 16:23:56",
"transactionEntryGeneralType": "CREDIT",
"transactionEntryDesignation": "TRANSACTION",
"transactionEntrySpecificType": "INBOUND_MSISDN_CREDIT"
},
{
"transactionSystemId": "ZPY210126171198TX",
"transactionReference": "4a7779f3-1575-5e3b-9561-48fbcab0bc76",
"transactionStatus": "SUCCEEDED",
"amount": 7450,
"msisdn": "256755329361",
"channel": "API",
"customerCharged": false,
"currencyCode": "UGX-ATLMM",
"currencyName": "Ugandan shillings (Airtel Money)",
"MNOTransactionReferenceId": "49758316690",
"transactionExternalReference": "21012620004480",
"transactionExternalNarrative": "Credit Note - 2101266096",
"transactionInitiationDate": "2021-01-26 20:00:44",
"transactionCompletionDate": "2021-01-26 20:00:54",
"transactionEntryGeneralType": "CREDIT",
"transactionEntryDesignation": "TRANSACTION",
"transactionEntrySpecificType": "INBOUND_MSISDN_CREDIT"
}
],
"first_page_url": "https://api.zengapay.com/v1/collections?page=1",
"from": 576,
"last_page": 24,
"last_page_url": "https://api.zengapay.com/v1/collections?page=24",
"links": [
{
"url": "https://api.zengapay.com/v1/collections?page=23",
"label": "pagination.previous",
"active": false
},
{
"url": "https://api.zengapay.com/v1/collections?page=1",
"label": 1,
"active": false
},
{
"url": "https://api.zengapay.com/v1/collections?page=2",
"label": 2,
"active": false
},
{
"url": null,
"label": "...",
"active": false
},
{
"url": "https://api.zengapay.com/v1/collections?page=24",
"label": 24,
"active": true
},
{
"url": null,
"label": "pagination.next",
"active": false
}
],
"next_page_url": null,
"path": "https://api.zengapay.com/v1/collections",
"per_page": 25,
"prev_page_url": "https://api.zengapay.com/v1/collections?page=23",
"to": 580,
"total": 580
}
}
Sending Money
Introduction
ZENGAPAY uses the term Transfers to refer to money that you send to a mobile subscriber. This differentiates money you send to mobile subscribers (aka Transfers) from money you receive from mobile subscribers (aka Collections).
ZENGAPAY provides the Transfers API to enable you to send money to a mobile subscriber, withdraw your funds, or to view transfers that you have previously sent to a mobile subscriber.
See the Transfers documentation below for more information.
Related Webhooks
The transfer.success
and transfer.failed
events are triggered whenever something happens to a transfer that you have initiated. For example, if it is successfully delivered or if it fails. You can configure a web link to receive notifications whenever this occurs. This will allow you to respond automatically whenever a transfer is completed or whenever it fails.
See our Webhooks API documentation for more information.
Transfers
To transfer money (mobile money) to a mobile subscriber, you create a new transfer object using the transfers API. You can also use the transfers API to retrieve individual transfers or list all transfers, as shown in the sections below.
The transfers api endpoint is:
Sample Transfer Request Object (JSON):
curl --location --request POST 'https://api.zengapay.com/v1/transfers' \
--header 'Authorization: Bearer <YOUR_API_TOKEN>' \
--header 'Content-Type: application/json' \
--data-raw '{
"msisdn":"256775203801",
"amount":256600,
"external_reference":"400000",
"narration":"Payout - 11200390191",
"use_contact":false}'
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.zengapay.com/v1/transfers",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS =>"{\"msisdn\":\"256775203801\",\"amount\":256600,\"external_reference\":\"400000\",\"narration\":\"Payout - 11200390191\",\"use_contact\":\"false\"\n}",
CURLOPT_HTTPHEADER => array(
"Authorization: Bearer <YOUR_API_TOKEN>",
"Content-Type: application/json"
),
));
$response = curl_exec($curl);
print_r($response);
require "uri"
require "net/http"
url = URI("https://api.zengapay.com/v1/transfers")
https = Net::HTTP.new(url.host, url.port);
https.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = "Bearer <YOUR_API_TOKEN>"
request["Content-Type"] = "application/json"
request.body = "{\"msisdn\":\"256775203801\",\"amount\":256600,\"external_reference\":\"400000\",\"narration\":\"Payout - 11200390191\"\n}"
response = https.request(request)
puts response.read_body
import requests
url = "https://api.zengapay.com/v1/transfers"
payload = "{\"msisdn\":\"256775203801\",\"amount\":256600,\"external_reference\":\"400000\",\"narration\":\"Payout - 11200390191\"\n}"
headers = {
'Authorization': 'Bearer <YOUR_API_TOKEN>',
'Content-Type': 'application/json'
}
response = requests.request("POST", url, headers=headers, data = payload)
print(response.text.encode('utf8'))
The Transfer Request object
Request in Postman
Parameter | Type | Description |
---|---|---|
msisdn | Integer (Required if use_contact is set to false) | The phone number that the collection request is intended for. Provide an internationally formatted number without the + . for example 256775203801 for MTN Uganda or 256755329361 for Airtel Uganda |
contact_id | UUID (Required if use_contact is set to true) | UUID the contact you are sending money to. eg 9aa3bc79-583e-4eb5-93bf-0e894b07aec9 . You can add contact using the Contacts API. |
amount | Float (Required) | The amount you want to transfer or payout eg 186600 or 186600.00 |
external_reference | String (Required) | Internal description or reason for this transfer request and must be unique for every request. For example, this may be an internal transaction identifier in your system. eg 000000018889191 |
narration | String (Required) | Textual narrative describing the transfer. eg Refund for Order - #0000001889191 |
use_contact | Boolean (Required) | A Boolean specifying to use contact_id or not eg true or false |
The above command returns JSON structured like this:
{
"code": 202,
"status": "accepted",
"message": "Transaction Initiated",
"transactionReference": "48f4be7a-73b3-524d-9a98-6290b56c5f2e"
}
Response sample in Postman
Retrieving a single Transfer (Verify Transfer Status)
To retrieve a single transfer object (verify status of a collection request), provide the transactionReference and a transfer object will be returned.
Request Parameters
Parameter | Type | Description |
---|---|---|
transactionReference | UUID | The reference to the transaction whose status you would like to follow up on. This is typically the transaction reference which came through as part of an earlier transfer request response. |
Sample Request:
curl --location --request GET 'https://api.zengapay.com/v1/transferss/ab1df360-3191-5e8a-acd6-c65281f22e9f' \
--header 'Authorization: Bearer <YOUR_API_TOKEN>'
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.zengapay.com/v1/transfers/ab1df360-3191-5e8a-acd6-c65281f22e9f",
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 => array(
"Authorization: Bearer <YOUR_API_TOKEN>"
),
));
$response = curl_exec($curl);
print_r($response);
require "uri"
require "net/http"
url = URI("https://api.zengapay.com/v1/transfers/ab1df360-3191-5e8a-acd6-c65281f22e9f")
https = Net::HTTP.new(url.host, url.port);
https.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = "Bearer <YOUR_API_TOKEN>"
response = https.request(request)
puts response.read_body
import requests
url = "https://api.zengapay.com/v1/transfers/ab1df360-3191-5e8a-acd6-c65281f22e9f"
payload = {}
headers = {
'Authorization': 'Bearer <YOUR_API_TOKEN>'
}
response = requests.request("GET", url, headers=headers, data = payload)
print(response.text.encode('utf8'))
Sample Response
The gateway will respond back with an object with this structure:
Response in displayed in Postman
Response Parameters
Parameter | Type | Description |
---|---|---|
transactionStatus | string | The status of the transaction, this can be one of these; PENDING ,SUCCEEDED ,FAILED ,INDETERMINATE |
transactionReference | string | The reference to the transaction requested |
MNOTransactionReferenceId | string | Mobile Network Operator (MNO) Transaction Reference Identifier. The value uniquely identifies this transaction on the relevant Mobile Network Operator's system. |
currencyCode | string | The currency code of the wallet currency in your merchant account where the amount paid by the customer will be deposited. |
msisdn | string | The mobile money account (phone number) where you are transferring the money to. |
amount | string | Amount requested for transfer |
channel | string | The Channel through which the transaction was initiated. this can be one of these; API ,WEB ,APP |
transactionType | string | The transaction type. for transfers this is usually OUTBOUND_MSISDN_CREDIT |
transactionInitiationDate | string | The transaction initiation date. This is of the format YYYY-MM-DD HH:mm:ss , e.g 2020-05-15 18:44:44 |
transactionCompletionDate | string | The transaction completion date. This is of the format YYYY-MM-DD HH:mm:ss , e.g 2020-05-15 18:44:55 . If the transaction is not yet complete, this will be set to 0000-00-00 00:00:00 |
Response:
{
"code": 200,
"status": "OK",
"data": {
"transactionSystemId": "ZPY201011098363TX",
"transactionReference": "950ec58b-8b90-5219-aecc-41520f7e540e",
"transactionStatus": "SUCCEEDED",
"amount": 3200,
"msisdn": "256755329361",
"channel": "API",
"currencyCode": "UGX-ATLMM",
"currencyName": "Ugandan shillings (Airtel Money)",
"MNOTransactionReferenceId": "44970884037",
"transactionExternalReference": "ENCPT730223314",
"transactionExternalNarrative": "Encapto MYUG 3k",
"transactionInitiationDate": "2020-10-11 12:44:04",
"transactionCompletionDate": "2020-10-11 12:44:09",
"transactionEntryGeneralType": "DEBIT",
"transactionEntryDesignation": "TRANSACTION",
"transactionEntrySpecificType": "OUTBOUND_MSISDN_DEBIT"
}
}
Retrieving all Transfers
To retrieve a list of all transfers, make a GET request to the collections endpoint. This will return a list of collection objects.
Response
{
"code": 200,
"status": "OK",
"transfers": {
"current_page": 1,
"data": [
{
"transactionSystemId": "ZPY200709074078TX",
"transactionReference": "4682c4c8-3180-50a3-8019-f77d1be6d778",
"transactionStatus": "SUCCEEDED",
"amount": 2700,
"msisdn": "256702983281",
"channel": "API",
"currencyCode": "UGX-ATLMM",
"currencyName": "Ugandan shillings (Airtel Money)",
"MNOTransactionReferenceId": "40879110750",
"transactionExternalReference": "32020490987",
"transactionExternalNarrative": "Payout June Salaries - BATCH-001",
"transactionInitiationDate": "2020-07-09 07:35:40",
"transactionCompletionDate": "2020-07-14 12:50:14",
"transactionEntryGeneralType": "DEBIT",
"transactionEntryDesignation": "TRANSACTION",
"transactionEntrySpecificType": "OUTBOUND_MSISDN_DEBIT"
},
{
"transactionSystemId": "ZPY200709074741TX",
"transactionReference": "e72bbb18-46c3-507e-9219-853af7945153",
"transactionStatus": "SUCCEEDED",
"amount": 2000,
"msisdn": "256702983281",
"channel": "API",
"currencyCode": "UGX-ATLMM",
"currencyName": "Ugandan shillings (Airtel Money)",
"MNOTransactionReferenceId": "40879505122",
"transactionExternalReference": "32020490987",
"transactionExternalNarrative": "Payout June Salaries - BATCH-001",
"transactionInitiationDate": "2020-07-09 07:45:17",
"transactionCompletionDate": "2020-07-14 12:50:14",
"transactionEntryGeneralType": "DEBIT",
"transactionEntryDesignation": "TRANSACTION",
"transactionEntrySpecificType": "OUTBOUND_MSISDN_DEBIT"
},
{
"transactionSystemId": "ZPY200810094152TX",
"transactionReference": "e07dcc6d-adda-5304-85b3-8bde22b35dac",
"transactionStatus": "SUCCEEDED",
"amount": 120000,
"msisdn": "256755329361",
"channel": "API",
"currencyCode": "UGX-ATLMM",
"currencyName": "Ugandan shillings (Airtel Money)",
"MNOTransactionReferenceId": "42241968168",
"transactionExternalReference": "200810223314",
"transactionExternalNarrative": "MTN Airtime Stock Purchase",
"transactionInitiationDate": "2020-08-10 12:51:06",
"transactionCompletionDate": "2020-08-10 12:51:09",
"transactionEntryGeneralType": "DEBIT",
"transactionEntryDesignation": "TRANSACTION",
"transactionEntrySpecificType": "OUTBOUND_MSISDN_DEBIT"
}
],
"first_page_url": "https://api.zengapay.com/v1/transfers?page=1",
"from": 1,
"last_page": 1,
"last_page_url": "https://api.zengapay.com/v1/transfers?page=1",
"links": [
{
"url": null,
"label": "pagination.previous",
"active": false
},
{
"url": "https://api.zengapay.com/v1/transfers?page=1",
"label": 1,
"active": true
},
{
"url": null,
"label": "pagination.next",
"active": false
}
],
"next_page_url": null,
"path": "https://api.zengapay.com/v1/transfers",
"per_page": 25,
"prev_page_url": null,
"to": 24,
"total": 24
}
}
Airtime
Sending Airtime
Voice & Data Bundles
Sending Voice or Data Bundle
Account
Account Summary
The accounts API method allows you to get a summary of your account.
Returned Rata
{
"code": 200,
"status": "OK",
"data": {
"account": [
{
"name": "MOMENTUM HOSTING LIMITED",
"number": "100835XXXXXX",
"category": "Business",
"address": "GPO Building, Kampala Road",
"official_email": "[email protected]",
"support_email": "[email protected]",
"website": "https://xxxxxxxxx.tld",
"created": "2020-06-10 22:02:51"
}
],
"balance": {
"currency": "UGX",
"available": 26194436.5,
"inWords": "Twenty Six Million, One Hundred Ninety Four Thousand, Four Hundred Thirty Six Shillings"
}
}
}
Account Balance
This Endpoint allows you to get the current break down of your merchant account balance.
The balance api endpoint is:
Returned Data
{
"code": 200,
"status": "OK",
"data": {
"balances": [
{
"currencyName": "Ugandan shillings (MTN Mobile Money)",
"currencyCode": "UGX-MTNMM",
"currencyProvider": "MTN Uganda Limited",
"available": 4806710
},
{
"currencyName": "Ugandan shillings (Airtel Money)",
"currencyCode": "UGX-ATLMM",
"currencyProvider": "Airtel Uganda Limited",
"available": 21387700
}
],
"balance": {
"available": 26194436.5,
"currency": "Ugandan shillings (UGX)",
"inWords": "Twenty Six Million, One Hundred Ninety Four Thousand, Four Hundred Thirty Six Shillings"
}
}
}
Account Statement
To retrieve a list of all transactions on your account (account statement), make a GET request to the statements end point. This will return a list of transactions.
The Account Statement api endpoint is:
Filtering Transactions
You can search or filter your statement using the following optional filters. Simply add them to your request as shown in the examples. You can also combine multiple filters.
Note that filters return exact matches only.
Filter | Type | Description |
---|---|---|
start | datetime | The earliest date you want to include transactions from, inclusive in the format YYYY-MM-DD HH:MM:SS |
end | datetime | The latest date you want to include transactions, inclusive in the format inclusive in the format YYYY-MM-DD HH:MM:SS |
status | string | Transaction Status. This can be FAILED , PENDING , INDETERMINATE , SUCCEEDED |
currency_code | string | This can be UGX-MTNMM for MTN or UGX-ATLMM for Airtel. |
limit | int | Total Number of transactions to be returned. eg 10. Default limit is 15 |
designation | string | Transaction entry Designation. This can be TRANSACTION or CHARGES . |
Request:
#Without filters (params)
curl --location --request GET 'https://api.zengapay.com/v1/account/statement' \
--header 'Authorization: Bearer <YOUR_API_TOKEN>'
#With Filters(params)
curl --location --request GET 'https://api.zengapay.com/v1/account/statement?start=2020-06-14 00:00:00&limit=5&end=2020-06-24 23:59:59' \
--header 'Authorization: Bearer <YOUR_API_TOKEN>'
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => "https://api.zengapay.com/v1/account/statement",
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 => array(
"Authorization: Bearer <YOUR_API_TOKEN>"
),
));
$response = curl_exec($curl);
print_r($response);
require "uri"
require "net/http"
url = URI("https://api.zengapay.com/v1/account/statement")
https = Net::HTTP.new(url.host, url.port);
https.use_ssl = true
request = Net::HTTP::Get.new(url)
request["Authorization"] = "Bearer <YOUR_API_TOKEN>"
response = https.request(request)
puts response.read_body
import requests
url = "https://api.zengapay.com/v1/account/statement"
payload = {}
headers = {
'Authorization': 'Bearer <YOUR_API_TOKEN>'
}
response = requests.request("GET", url, headers=headers, data = payload)
print(response.text.encode('utf8'))
Response
{
"code": 200,
"status": "OK",
"statement": {
"current_page": 1,
"data": [
{
"transactionSystemId": "ZPY200806082352TX",
"transactionReference": "6f32e807-2973-55a3-8a48-d4d1732311c1",
"transactionStatus": "SUCCEEDED",
"amount": 256600,
"msisdn": "256755329361",
"channel": "API",
"currencyCode": "UGX-ATLMM",
"currencyName": "Ugandan shillings (Airtel Money)",
"balanceBeforeTransaction": 4794120,
"balanceAfterTransaction": 5050720,
"transactionExternalReference": "20080611265235",
"transactionExternalNarrative": "Service Setup - dohgov.co",
"transactionInitiationDate": "2020-08-06 11:26:53",
"transactionCompletionDate": "2020-08-06 11:27:04",
"transactionEntryGeneralType": "CREDIT",
"transactionEntryDesignation": "TRANSACTION",
"transactionEntrySpecificType": "INBOUND_MSISDN_CREDIT"
},
{
"transactionSystemId": "ZPY200806116741TX",
"transactionReference": "8ae8aefe-d555-5aa9-8c6c-03af8b7cb345",
"transactionStatus": "SUCCEEDED",
"amount": 5132,
"msisdn": null,
"channel": "BACK_END_PROCESSOR",
"currencyCode": "UGX-ATLMM",
"currencyName": "Ugandan shillings (Airtel Money)",
"balanceBeforeTransaction": 5050720,
"balanceAfterTransaction": 5045580,
"transactionExternalReference": "ZPY200806082352TX",
"transactionExternalNarrative": "AIRTEL_UGANDA 2PC DEPOSITS CHARGE FOR TRANSACTION ID #ZPY200806082352TX",
"transactionInitiationDate": "2020-08-06 11:27:04",
"transactionCompletionDate": "2020-08-06 11:27:04",
"transactionEntryGeneralType": "DEBIT",
"transactionEntryDesignation": "CHARGES",
"transactionEntrySpecificType": "OUTBOUND_ZPACCT_DEBIT"
},
{
"transactionSystemId": "ZPY200806112526TX",
"transactionReference": "62eb9bbc-520a-58b1-bee9-2f1da582ab64",
"transactionStatus": "SUCCEEDED",
"amount": 5000,
"msisdn": "256755329361",
"channel": "API",
"currencyCode": "UGX-ATLMM",
"currencyName": "Ugandan shillings (Airtel Money)",
"balanceBeforeTransaction": 5045580,
"balanceAfterTransaction": 5050580,
"transactionExternalReference": "20080614441078",
"transactionExternalNarrative": "Credit Note - 2008068160",
"transactionInitiationDate": "2020-08-06 14:44:10",
"transactionCompletionDate": "2020-08-06 14:44:23",
"transactionEntryGeneralType": "CREDIT",
"transactionEntryDesignation": "TRANSACTION",
"transactionEntrySpecificType": "INBOUND_MSISDN_CREDIT"
},
{
"transactionSystemId": "ZPY200806141884TX",
"transactionReference": "e71122c3-34c5-58e2-b3a4-efa831560b52",
"transactionStatus": "SUCCEEDED",
"amount": 100,
"msisdn": null,
"channel": "BACK_END_PROCESSOR",
"currencyCode": "UGX-ATLMM",
"currencyName": "Ugandan shillings (Airtel Money)",
"balanceBeforeTransaction": 5050580,
"balanceAfterTransaction": 5050480,
"transactionExternalReference": "ZPY200806112526TX",
"transactionExternalNarrative": "AIRTEL_UGANDA 2PC DEPOSITS CHARGE FOR TRANSACTION ID #ZPY200806112526TX",
"transactionInitiationDate": "2020-08-06 14:44:23",
"transactionCompletionDate": "2020-08-06 14:44:23",
"transactionEntryGeneralType": "DEBIT",
"transactionEntryDesignation": "CHARGES",
"transactionEntrySpecificType": "OUTBOUND_ZPACCT_DEBIT"
},
{
"transactionSystemId": "ZPY200806176137TX",
"transactionReference": "9122712b-6f0c-54ff-ab53-515b8d29fae4",
"transactionStatus": "SUCCEEDED",
"amount": 107610,
"msisdn": "256784553576",
"channel": "API",
"currencyCode": "UGX-MTNMM",
"currencyName": "Ugandan shillings (MTN Mobile Money)",
"balanceBeforeTransaction": 1396870,
"balanceAfterTransaction": 1504480,
"transactionExternalReference": "20080620471018",
"transactionExternalNarrative": "Service Setup - afcedugc.net",
"transactionInitiationDate": "2020-08-06 20:47:10",
"transactionCompletionDate": "2020-08-06 20:47:34",
"transactionEntryGeneralType": "CREDIT",
"transactionEntryDesignation": "TRANSACTION",
"transactionEntrySpecificType": "INBOUND_MSISDN_CREDIT"
},
{
"transactionSystemId": "ZPY200806205562TX",
"transactionReference": "ac24cc4d-56b7-53ee-9070-579aa9afa8a4",
"transactionStatus": "SUCCEEDED",
"amount": 2152.2,
"msisdn": null,
"channel": "BACK_END_PROCESSOR",
"currencyCode": "UGX-MTNMM",
"currencyName": "Ugandan shillings (MTN Mobile Money)",
"balanceBeforeTransaction": 1504480,
"balanceAfterTransaction": 1502330,
"transactionExternalReference": "ZPY200806176137TX",
"transactionExternalNarrative": "MTN_UGANDA 2PC DEPOSITS CHARGE FOR TRANSACTION ID #ZPY200806176137TX",
"transactionInitiationDate": "2020-08-06 20:47:35",
"transactionCompletionDate": "2020-08-06 20:47:35",
"transactionEntryGeneralType": "DEBIT",
"transactionEntryDesignation": "CHARGES",
"transactionEntrySpecificType": "OUTBOUND_ZPACCT_DEBIT"
}
],
"first_page_url": "https://api.zengapay.com/v1/account/statement?page=1",
"from": 1,
"last_page": 1,
"last_page_url": "https://api.zengapay.com/v1/account/statement?page=1",
"links": [
{
"url": null,
"label": "pagination.previous",
"active": false
},
{
"url": "https://api.zengapay.com/v1/account/statement?page=1",
"label": 1,
"active": true
},
{
"url": null,
"label": "pagination.next",
"active": false
}
],
"next_page_url": null,
"path": "https://api.zengapay.com/v1/account/statement",
"per_page": 25,
"prev_page_url": null,
"to": 6,
"total": 6
}
}
Contacts
Introduction
Contacts represent people whom you can send payments to. The Contacts API Method allows you to add, retrieve, list and update contacts in your account. Contacts are also added automatically whenever you send a payment to a new phone number.
The contacts api endpoint is:
Creating a Contact
To Add a contact, simply send a POST request to the below
Parameter | Type | Description |
---|---|---|
first_name | String (Required) | First Name. |
last_name | String (Optional) | Last Name. |
phone | digits (Required) | The MSISDN/Phone Number eg 256775000001 or 256755000001 |
type | String (Required) | Contact Type. This can be one of the following Beneficiary ,Employee ,Vendor ,Other |
Response:
{
"code": 201,
"status": "success",
"uuid": "0add25f6-88a0-5979-8ee8-4dcf19f548e6",
"message": "Contact added successfully"
}
Getting All Contacts
To retrieve a list of all your contacts, make a GET request to the contacts end point. This will return a list of all your contacts.
The Account Statement api endpoint is:
Response
{
"code": 200,
"status": "success",
"contacts": {
"current_page": 1,
"data": [
{
"name": "Denis Ojok",
"phone": "256775203801",
"type": "Beneficiary",
"network": "MTN UGANDA",
"active": true,
"uuid": "0add25f6-88a0-5979-8ee8-4dcf19f548e6",
"created": "2021-06-29 16:35:55",
"updated": "2021-06-29 16:35:55"
},
{
"name": "Denis",
"phone": "256755000001",
"type": "Beneficiary",
"network": "AIRTEL UGANDA",
"active": true,
"uuid": "d8ab8bbe-c864-5fe3-870f-e3c3165b4ce6",
"created": "2021-06-29 17:14:15",
"updated": "2021-06-29 17:14:15"
}
],
"first_page_url": "https://api.zengapay.com/v1/contacts?page=1",
"from": 1,
"last_page": 1,
"last_page_url": "https://api.zengapay.com/v1/contacts?page=1",
"links": [
{
"url": null,
"label": "pagination.previous",
"active": false
},
{
"url": "https://api.zengapay.com/v1/contacts?page=1",
"label": "1",
"active": true
},
{
"url": null,
"label": "pagination.next",
"active": false
}
],
"next_page_url": null,
"path": "https://api.zengapay.com/v1/contacts",
"per_page": 25,
"prev_page_url": null,
"to": 2,
"total": 2
}
}
Networks
Introduction
The Networks API Method allows you to list all the networks supported by the ZENGAPAY API, including information like country, network and currency prefixes for each network/country
The contacts api endpoint is:
Get All Networks
cURL Request:
curl --location --request GET 'https://api.zengapay.com/v1/networks' \
--header 'Authorization: Bearer <YOUR_API_TOKEN>'
Request in Postman
Response
{
"code": 200,
"status": "OK",
"networks": {
"current_page": 1,
"data": [
{
"id": 1,
"networkName": "MTN Uganda Limited",
"serviceName": "MTN Mobile Money",
"currencyName": "Ugandan shillings (MTN Mobile Money)",
"currencyCode": "UGX-MTNMM",
"country": "UGANDA",
"countryIso2": "UG"
},
{
"id": 2,
"networkName": "Airtel Uganda Limited",
"serviceName": "Airtel Money",
"currencyName": "Ugandan shillings (Airtel Money)",
"currencyCode": "UGX-ATLMM",
"country": "UGANDA",
"countryIso2": "UG"
}
],
"first_page_url": "https://api.zengapay.com/v1/networks?page=1",
"from": 1,
"last_page": 1,
"last_page_url": "https://api.zengapay.com/v1/networks?page=1",
"next_page_url": null,
"path": "https://api.zengapay.com/v1/networks",
"per_page": 15,
"prev_page_url": null,
"to": 2,
"total": 2
}
}
Retrieving a Single Network
To retrieve a single network, provide the network id and a network object will be returned.
Request Parameters
Parameter | Type | Required ? | Description |
---|---|---|---|
id | Integer | Yes | The id of the network you want to retrieve. eg 2 for AIRTEL UGANDA LIMITED |
cURL Request:
curl --location --request GET 'https://api.zengapay.com/v1/networks/2' \
--header 'Authorization: Bearer <YOUR_API_TOKEN>'
Request in Postman
Response
{
"code": 200,
"status": "OK",
"network": {
"networkName": "Airtel Uganda Limited",
"serviceName": "Airtel Money",
"currencyName": "Ugandan shillings (Airtel Money)",
"currencyCode": "UGX-ATLMM",
"country": "UGANDA",
"countryIso2": "UG"
}
}
Banks
Introduction
This api allows the users to check which banks are supported by the ZENGAPAY API. The API endpoint is
The banks api endpoint is:
Webhooks
Rather than build and manage a system to verify transactions endlessly, we encourage you to embrace our "don't call us, we will call you" maxim. Handle webhooks.
Whenever actions are carried out on your ZENGAPAY Account, we trigger events which your application can hook into.
This is where webhooks come in.
You can set this up on your dashboard by specifying a URL we would send POST requests to whenever something interesting happens such as a collection or transfer.
Tips for a good webhook url
- If using .htaccess, remember to add the trailing / to the url you set.
- Do a test post to your URL and ensure the script gets the post body.
- Publicly available url (http://localhost cannot receive!)
- Use a secure webhook url. Therefore
only https urls can be set or called-back
.
Setting a webhook
Go to Account Settings
Click the Developer Settings.
Set the WEBHOOK URL field with your WEBHOOK URL eg.
https://exmaple.org/callback
Set the Secret Hash. A secret hash is used to verify your webhook requests.
Enable Webhooks
Receiving a Webhook
- We will call your webhook url whenever the transaction status changes.
- You will need to acknowledge receipt of the callback by responding with a
200
,201
or202
HTTP status code (We recommend returning a202
Status).
Creating an endpoint to receive web hooks on your application is as easy as creating a new page that accepts unauthenticated POST requests. The webhook object is sent as JSON in the request body.
You may also use the following services to test and verify webhooks before pointing the webhook url to your servers.
Receiving a Webhook
Node.js
// Using Express
app.post("/my/webhook/url", function(req, res) {
// Retrieve the request's body
var event = req.body;
// Do something with event
res.send(202);
});
<?php
// Retrieve the request's body and parse it as JSON
$input = @file_get_contents("php://input");
$event = json_decode($input);
// Do something with $event
http_response_code(200); // PHP 5.4 or greater
?>
Verifying and Validating a webhook
To ensure that the callback data sent to your webhook URL comes from our servers, you need to set a secret-hash under the API Settings.
We will include a header called X-ZENGAPAY-SIGNATURE in the request sent to the callback url. e.g
"X-ZENGAPAY-SIGNATURE: XXXX"
which is essentially a HMAC SHA256 signature of the transaction payload (transactionReference
+msisdn
+amount
). Yes, signed using your secret hash..
Sample PHP implementation to generate verification signature:
<?php
// only a post with ZENGAPAY signature header gets our attention
if ((strtoupper($_SERVER['REQUEST_METHOD']) != 'POST') || !array_key_exists('HTTP_X_ZENGAPAY_SIGNATURE', $_SERVER))
exit();
// Retrieve the request's body
$input = @file_get_contents("php://input");
define('YOUR_SECRET_HASH','SECRET_HASH'); // Same as that set in your ZENGAPAY Webhook settings
// validate event do all at once to avoid timing attack
if($_SERVER['HTTP_X_ZENGAPAY_SIGNATURE'] !== hash_hmac('sha256', $input, YOUR_SECRET_HASH))
exit();
// Where $input is concatenated string containing `transactionReference`+`msisdn`+`amount`
http_response_code(202);
// parse callback data (which is json string) as object
// Do something - that will not take long - with $data
$data = json_decode($input);
exit();
Responding to webhooks
To acknowledge receipt of a webhook, your endpoint should return a 200
, 201
or 202
HTTP status code (We recommend returning a 202
Status).
If your server responds with any other http status code other than those mentioned above, ZENGAPAY will retry it up to 3 times to resend the webhook before giving up.
If your endpoint does not successfully receive a webhook for any reason, webhooks would not be retried, though you can query for the status using the GET transaction
endpoint to reconcile your data with any missed events.
Structure of a webhook object
A webhook object object is sent in JSON and similar to what you would get in response to a typical API request. Well, the data bit of it. Below is the body of an event that was fired when we created a collection request . The other tabs highlight the structure of other types of webhooks
collection.success Webhook
{
{
"event": "collection.success",
"data": {
"transactionSystemId": "ZPY211025129553TX",
"transactionReference": "20570a12-c92b-5893-b7df-91ea54a0af34",
"transactionStatus": "SUCCEEDED",
"amount": "5000",
"msisdn": "256392003738",
"channel": "API",
"customerCharged": "false",
"currencyCode": "UGX-MTNMM",
"currencyName": "Ugandan Shillings (MTN Mobile Money)",
"MNOTransactionReferenceId": "13981886537",
"transactionExternalReference": "21102515185381",
"transactionExternalNarrative": "Credit Note - 2110251981",
"transactionInitiationDate": "2021-10-25 15:18:53",
"transactionCompletionDate": "2021-10-25 15:19:05",
"transactionEntryGeneralType": "CREDIT",
"transactionEntryDesignation": "TRANSACTION",
"transactionEntrySpecificType": "INBOUND_MSISDN_CREDIT"
}
}
}
Errors
The ZENGAPAY API uses the following error codes:
Code | Meaning |
---|---|
400 | Bad Request -- Your request is invalid. |
401 | Unauthorized -- Your API key is wrong. |
403 | Forbidden -- Access to the requested resource is forbidden for some reason. |
404 | Not Found -- The specified transaction or resource could not be found. |
405 | Method Not Allowed -- You tried to access an endpoint with an invalid method. |
406 | Not Acceptable -- You requested a format that isn't json. |
422 | Unprocessable Entity -- A required field was missing or invalid |
429 | Too Many Requests -- You have reached your API call(s) rate limit. |
500 | Internal Server Error -- We had a problem with our server. Try again later. |
503 | Service Unavailable -- We're temporarily offline for maintenance. Please try again later. |