Botswana
The 54Pay Collections API enables merchants to accept payments through prepaid voucher systems in Botswana. This payment method digitizes cash for online transactions, functioning similarly to airtime vouchers but working like bank cards.
Key Characteristics
Unlike mobile money implementations in other markets, Botswana's voucher system operates through a validate-and-redeem workflow that processes prepaid voucher PINs instead of initiating real-time mobile money transfers.
Authentication
All API requests require the following HTTP headers:
| Header | Type | Description |
|---|---|---|
| X-module | string | Base64(amount+transactionReference+customerNumber) |
| X-business | string | Base64-encoded Merchant Public Key: {Base64(Merchant Public Key)} |
| Content-Type | string | Must be application/json |
| x-app | string | Must be api |
Integration Methods
The API supports two distinct integration methods determined by the requestType passed in the request header. You must choose the method that best aligns with your business logic:
- Integration Method A (
"requestType": "A") — Strict Validation: The voucher amount is strictly validated against thetransactionAmountpassed in your API request. If the requestedtransactionAmountdoes not exactly match the actual value of the prepaid voucher, the transaction will be rejected. - Integration Method B (
"requestType": "B") — Flexible Processing: The voucher will be processed and redeemed for its actual underlying value, regardless of thetransactionAmountpassed in your API request.
Because the redeemed amount may differ from the requested amount, you must use the amount_received field in the asynchronous webhook payload to determine the actual value to credit the customer. Failing to do so may result in giving the customer more value than the voucher is worth.
Initiate Collection
Processes a payment transaction using a prepaid voucher PIN.
Endpoint: POST https://subsidiary.dev.mypaygate.co/collection/v1/payin
Sample Request
curl --location 'https://subsidiary.dev.mypaygate.co/collection/v1/payin' --header 'X-module: MTBUWE40MjkwNTU3ODIyMDc3MDAwMDA=' --header 'X-business: {Base64(Merchant Public Key)}' --header 'Content-Type: application/json' --header 'X-app: api' --data-raw '{
"requestHeader": {
"clientId": "",
"requestType": "A"
},
"customerName": "Ayo Akin",
"customerEmail": "user@gmail.com",
"customerNumber": "26772345684",
"voucherPin": "1234567890123456",
"transactionReference": "TXN50518093",
"transactionDescription": "Test",
"transactionAmount": 100,
"transactionCurrency": "BWP",
"transactionCountry": "BW",
"successUrl": "",
"errorUrl": "",
"cancelUrl": "",
"operatorCode": "BWVCH",
"webhookUrl": ""
}'
Set "requestType": "A" or "requestType": "B" depending on your preferred integration method.
Success Response Example
{
"responseDetails": {
"responseCode": "00",
"responseMessage": "COMPLETED"
},
"transactionReference": "TXN50518093",
"otpIsRequired": false,
"lengthOfOtp": 0,
"paymentCompletionRequired": false
}
Error Response Examples
Invalid Voucher:
{
"responseDetails": {
"responseCode": "06",
"responseMessage": "FAILED",
"failedReason": "Invalid Voucher",
"voucherPurchaseWebsite": "https://www.paybills.co.bw/#/OTT"
},
"transactionReference": "TXN_20241215_001"
}
Amount Mismatch (only when using requestType: A):
{
"responseDetails": {
"responseCode": "06",
"responseMessage": "FAILED",
"failedReason": "Voucher value does not match transaction amount",
"voucherPurchaseWebsite": "https://www.paybills.co.bw/#/OTT"
},
"transactionReference": "TXN_20241215_001"
}
Expired Voucher:
{
"responseDetails": {
"responseCode": "06",
"responseMessage": "FAILED",
"failedReason": "VOUCHER EXPIRED",
"voucherPurchaseWebsite": "https://ottbotswana.com/vouchers"
},
"transactionReference": "TXN_20241215_001"
}
Test Voucher PINs
| Voucher PIN | Amount (BWP) | Expected Behavior |
|---|---|---|
| 1234567890123456 | 100 | Returns successful response |
| 1111111111111111 | 100 | Always returns "Invalid Voucher" error |
Webhooks
amount_receivedThe amount_received field in the webhook payload represents the actual, real-world value of the remitted voucher — not the transactionAmount sent in your original API request.
If you are using Integration Method B (requestType: B): It is absolutely critical that you always use the amount_received field from the webhook payload to validate and credit the customer's account. Using the original request amount can result in crediting the customer with more value than the physical voucher was worth.
Payment Status Webhook
Implement webhook handlers to receive asynchronous transaction status updates.
Sample Webhooks - Success
{
"transaction_reference": "PG-C-176590537521970",
"transaction_status": "Funds Received",
"transaction_fee": 5,
"amount_received": 100,
"initiated_date": "2025-12-16 18:16:15",
"current_status_date": "2025-12-16 18:16:15",
"received_from": {},
"merchant_reference": "TXN50518093",
"status": "COMPLETED",
"currency_code": "BWP"
}
Sample Webhooks - Failed
{
"transaction_reference": "PG-C-176587434198385",
"transaction_status": "Transaction Failed",
"transaction_fee": 0,
"amount_received": 100,
"initiated_date": "2025-12-16 09:39:01",
"current_status_date": "2025-12-16 09:39:02",
"received_from": {},
"merchant_reference": "TXN15414935",
"status": "FAILED",
"currency_code": "BWP",
"failure_reason": "Invalid Voucher"
}
Webhook Status Values
| Status | Description |
|---|---|
| COMPLETED | Payment successfully received and voucher redeemed. |
| FAILED | Payment failed, voucher invalid, or voucher expired. |
Webhook Implementation
Your webhook endpoint must:
- Accept POST requests: Listen for incoming webhook notifications.
- Validate payload: Verify merchant_reference matches your internal records.
- Return 200 OK: Respond within 5 seconds to acknowledge receipt.
- Process asynchronously: Handle your business logic (like crediting the user based on
amount_received) after responding with a 200 OK. - Handle duplicates: Implement idempotency checks using
transaction_reference.
Webhook Security
To ensure webhook authenticity:
- Verify requests originate strictly from 54Pay IP addresses.
- Validate that the merchant_reference exists and is pending in your system.
- Store webhook payloads for a historical audit trail.