POST https://mybundlepay.com/ng/api/v2/virtual-card/topup
KEY USAGE POLICY
Important: Use your test_secret_key for sandbox testing.
Switch to live_secret_key only when you are ready to go live.
- Test calls return mock data and do not process real transactions.
- Live calls top-up real virtual cards.
- Ensure your server IP is whitelisted before calling live endpoints.
⚠️ Do not use live keys for testing — unauthorized IPs will be blocked.
HEADERS
Authorization * string
Send your {secret_key} as a Bearer token in the header.
Content-Type * application/json
All requests must use JSON body format.
IP WHITELISTING
Only authorized server IPs can access this endpoint. Whitelist your IP in MyBundlePay Dashboard.
BODY PARAMS
| Parameter | Required | Description |
|---|---|---|
amount |
✅ | Amount to top-up (USD). Minimum $1. |
cardId |
✅ | Unique card ID to top up (retrieved from card creation response). |
reference |
✅ | Unique reference for this transaction. Must be unique per top-up. |
<?php
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://mybundlepay.com/ng/api/v2/virtual-card/topup',
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 =>'{
"amount": "1",
"cardId": "xxxxx-a228-4ec2-9337-xxxxx",
"reference": "MBP-TEST-amount006"
}',
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json',
'Authorization: Bearer {secret_key}'
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
?>
const axios = require('axios');
const data = {
amount: "1",
cardId: "xxxxx-a228-4ec2-9337-xxxxx",
reference: "MBP-TEST-amount006"
};
axios.post("https://mybundlepay.com/ng/api/v2/virtual-card/topup", data, {
headers: {
"Content-Type": "application/json",
"Authorization": "Bearer {secret_key}"
}
})
.then(res => console.log(res.data))
.catch(err => console.error(err.response ? err.response.data : err.message));
✅ Success Response
{
"status": "success",
"message": "Card top-up initiated successfully. Get confirmation from webhook.",
"data": {
"provider_response": {
"status": true,
"message": "card topup in progress",
"data": {
"id": "xxxxxx-67f0-4fd0-aa7a-xxxxxxx",
"type": "credit",
"method": "topup",
"cardId": "xxxxx-a228-4ec2-9337-xxxxx",
"currency": "usd",
"centAmount": "100",
"status": "pending",
"reference": "MBP-TEST-amount006",
"amount": "1"
}
},
"reference": "MBP-TEST-amount006",
"amount": "1"
},
"mode": "test"
}
❌ Error Response (IP Not Authorized)
{
"status": "failed",
"code": "IP_NOT_AUTHORIZED",
"message": "Your IP is not authorized for API access.",
"ip": "54.86.50.139",
"mode": "live"
}
❌ Error Response (Invalid Amount)
{
"status": "failed",
"code": "INVALID_AMOUNT",
"message": "The minimum top-up amount is $1. Amount must be 1 or higher.",
"errors": {
"amount": [
"The minimum top-up amount is 1."
]
},
"mode": "test"
}
❌ Error Response (Missing Params)
{
"status": "failed",
"message": "All body parameters are required: amount, cardId, reference.",
"errors": {
"amount": ["The amount field is required."],
"cardId": ["The card id field is required."],
"reference": ["The reference field is required."]
},
"mode": "test"
}
❌ Error Response (Duplicate Reference)
{
"status": "failed",
"message": "All body parameters are required: amount, cardId, reference.",
"errors": {
"reference": ["The reference has already been taken."]
},
"mode": "test"
}