1curl -X POST 'https://api.budpay.com/api/s2s/test/encryption' \2 -H 'Content-Type: application/json' \3 -H 'Authorization: Bearer YOUR_SECRET_KEY' \4 -d '{5 "data": {6 "number": "4242424242424242",7 "cvv": "123",8 "expiryMonth": "12",9 "expiryYear": "28",10 "pin": "1234"11 },12 "reference": "1234567890123456"13}'Server to Server (Cards)
The Direct Charge API lets you charge Visa, Mastercard and Verve cards (NGN) from your own checkout, without redirecting the customer to a BudPay page. You collect the card details, encrypt them, and send them to BudPay from your server.
How it works
- Collect card details. Capture the customer's card details in your own checkout form.
- Encrypt the card details. Encrypt the card details with AES-256-CBC before they leave your system.
- Initialize the transaction. Send the encrypted card to the S2S
initializeendpoint. - Complete 3D Secure. If the card requires 3D Secure, complete the authentication flow described in Step 4.
- Verify the transaction. Confirm the final status with the
verifyendpoint before you give value.
Step 1: Collect Card Details
Collect the customer's card details in your checkout. Handling raw card data brings your systems into PCI DSS scope, so make sure your environment is compliant before you go live. You need the following details:
{
"data": {
"number": "4242424242424242",
"cvv": "123",
"expiryMonth": "12",
"expiryYear": "28",
"pin": "1234" // optional - only required for verve/local cards
},
"reference": "1234567890123456"
}| Field | Description |
|---|---|
number | The card number. |
cvv | The card verification value (CVV) on the back of the card. |
expiryMonth | The card's expiry month, 2 digits, e.g. "12". |
expiryYear | The card's expiry year, 2 digits, e.g. "28" for 2028. |
pin | The card PIN. Required for Verve and other local cards only. |
reference | A unique reference for the transaction, at least 16 characters long. The first 16 characters are used to encrypt the card. |
Step 2: Encrypt the Card Details
Encrypt the card details with AES-256-CBC before you send them to BudPay. The examples below show how to do this in Node.js and PHP.
Encryption Parameters
| Parameter | Description |
|---|---|
data | The card details to be encrypted. |
key | The encryption key. Use your BudPay public key. |
reference | The unique transaction reference. It must be at least 16 characters long. |
iv | The initialization vector: the first 16 characters of the reference. |
encryptionType | The encryption algorithm and mode: aes-256-cbc. |
const crypto = require('crypto');
function cardEncryption() {
const data = {
number: "5123450000000008", // Card Number
expiryMonth: "10", // Card Expiry Month
expiryYear: "28", // Card Expiry Year
cvv: "100", // Card CVV
pin: "1234" // (Optional - only required for verve/local cards)
};
const key = 'BUDPAY_PUBLIC_KEY'; // Encryption Key: BudPay Public key used for encryption
const reference = "10033333333333333"; // 16 Digits Minimum
const iv = reference.slice(0, 16); // Initialization Vector: A fixed-size input for the cryptographic algorithm to ensure uniqueness
const encryptionType = 'aes-256-cbc'; // Encryption Type: Specifies the encryption algorithm and mode
// Convert key to Buffer for crypto library
const keyBuffer = Buffer.from(key, 'utf-8');
// Convert iv to Buffer for crypto library
const ivBuffer = Buffer.from(iv, 'utf-8');
// Create a Cipher object
const cipher = crypto.createCipheriv(encryptionType, keyBuffer, ivBuffer);
// Encrypt the data
let encryptedData = cipher.update(JSON.stringify(data), 'utf-8', 'hex');
encryptedData += cipher.final('hex');
return encryptedData;
}
console.log(cardEncryption());cardEncryption returns the encrypted card details as a hexadecimal string. Send this value as card in Step 3.
Test Your Encryption
Use the test encryption endpoint to check your implementation. Encrypt the same card details and reference in your code, then compare your output with the value returned by this endpoint. If they match, your encryption is correct.
This endpoint is for testing only. In production, always encrypt card details in your own code.
Headers
| Parameter | Description |
|---|---|
URL | https://api.budpay.com/api/s2s/test/encryption (opens in a new tab) |
Method | POST |
Content-Type | The content type of the request. Set this to application/json. |
Authorization | The secret key used to authenticate the request, set this to Bearer YOUR_SECRET_KEY. |
Endpoint: POST https://api.budpay.com/api/s2s/test/encryption
Sample Response
{
"card": "83fa6763bb31bae36a74f787ab814514aeede91fcdb311fd67609b414c5e5ea2751a47870c8717e71bcbc9c33287a3d6af9ffae8e2edbf2de1e2694384d699b020d31492637eef60d7a63f303798363a"
}Step 3: Initialize the Transaction
Send the encrypted card details to the S2S initialize endpoint from your server.
Endpoint: POST https://api.budpay.com/api/s2s/transaction/initialize
1curl -X POST 'https://api.budpay.com/api/s2s/transaction/initialize' \2 -H 'Content-Type: application/json' \3 -H 'Authorization: Bearer YOUR_SECRET_KEY' \4 -d '{5 "amount": "100",6 "card": "83fa6763bb31bae36a74f787ab814514aeede91fcdb311fd67609b414c5e5ea2751a47870c8717e71bcbc9c33287a3d6af9ffae8e2edbf2de1e2694384d699b020d31492637eef60d7a63f303798363a",7 "currency": "NGN",8 "email": "test@email.com",9 "reference": "1253627873656276350"10}'Sample Request Body
{
"card": "83fa6763bb31bae36a74f787ab814514aeede91fcdb311fd67609b414c5e5ea2751a47870c8717e71bcbc9c33287a3d6af9ffae8e2edbf2de1e2694384d699b020d31492637eef60d7a63f303798363a",
"pin": "1234", // optional - only required for verve/local cards
"amount": 10000,
"currency": "NGN",
"email": "test@gmail.com",
"callback": "https://yourwebsite.com/callback",
"reference": "1234567890123456"
}Headers
| Parameter | Description |
|---|---|
URL | https://api.budpay.com/api/s2s/transaction/initialize (opens in a new tab) |
Method | POST |
Content-Type | The content type of the request. Set this to application/json. |
Authorization | The secret key used to authenticate the request, set this to Bearer YOUR_SECRET_KEY. |
Request Body
| Parameter | Type | Required | Description |
|---|---|---|---|
card | string | Yes | The encrypted card details from Step 2. |
amount | string | Yes | The amount to charge. |
currency | string | Yes | The transaction currency. |
email | string | Yes | The customer's email address. |
callback | string | Yes | The URL to redirect the customer to after the transaction. |
reference | string | Yes | The same reference you used to encrypt the card. |
pin | string | No | The card PIN. Required for Verve and other local cards only. |
Step 4: Complete 3D Secure Authentication
If the card supports 3D Secure 2 (3DS2), the initialize endpoint returns an HTML snippet in data and a follow-up request in _links:
3DS2 Response
{
"status": true,
"message": "Proceed authentication 3DS2",
"data": "<div id=\"initiate3dsSimpleRedirect\" xmlns=\"http://www.w3.org/1999/html\"> <iframe id=\"methodFrame\" name=\"methodFrame\" height=\"100\" width=\"200\" > </iframe> <form id =\"initiate3dsSimpleRedirectForm\" method=\"POST\" action=\"https://secure-acs2ui-b1.wibmo.com/v1/acs/services/threeDSMethod/8528?cardType=M\" target=\"methodFrame\"> <input type=\"hidden\" name=\"threeDSMethodData\" value=\"eyJ0aHJlZURTTWV0aG9kTm90aWZpY2F0aW9uVVJMIjoiaHR0cHM6Ly9ldS5nYXRld2F5Lm1hc3RlcmNhcmQuY29tL2NhbGxiYWNrSW50ZXJmYWNlL2dhdGV3YXkvOGFkZGRiNzE1MTQwMjk2OWMxMmI1Y2QzNjBhOTdmYTdiZTE1ZWU1NWZiZDEwZTE5MmI3ZDIwNDcxNmQxYTVlNSIsInRocmVlRFNTZXJ2ZXJUcmFuc0lEIjoiZjgxNGM3YWMtMmRiOS00Nzg1LThhMjYtYjA2NjZlYTBjMGVkIn0=\" /> </form> <script id=\"initiate-authentication-script\"> var e=document.getElementById(\"initiate3dsSimpleRedirectForm\"); if (e) { e.submit(); if (e.parentNode !== null) { e.parentNode.removeChild(e); } } </script> </div>",
"_links": {
"url": "http://api.budpay.com/api/mastercard-payment/3ds2auth",
"method": "POST",
"payload": [
"ref"
]
}
}To complete authentication:
- Render the HTML in
datain a hidden iframe on your checkout page. It submits the card's 3DS2 device data to the issuing bank. - Wait 20 seconds for the process to complete.
- Send a request to the
_links.urlendpoint, using the_links.methodand the fields listed in_links.payload. - Handle the final response below.
Cards that do not support 3DS2 skip this step. The initialize endpoint returns the final response directly.
3DS2 Flow Diagram
Final Response
The final response is returned after 3DS2 authentication, or directly from initialize for cards that don't use 3DS2.
Mastercard and Visa
{
"status": "success",
"message": "Approved or Captured"
}Verve
{
"status": true,
"message": "Payment Successful"
}Before giving value, confirm that status is successful and that message is "Approved" or "Captured". Then verify the transaction with the endpoint below.
Verifying Transactions
Call the Verify Transaction API with the transaction reference:
GET https://api.budpay.com/api/v2/transaction/verify/:referenceExample Request:
Endpoint: GET https://api.budpay.com/api/v2/transaction/verify/BUD_1673600359168063493
1curl -X GET 'https://api.budpay.com/api/v2/transaction/verify/BUD_1673600359168063493' \2 -H 'Authorization: Bearer YOUR_SECRET_KEY'{ "status": true, "message": "Transaction verified successfully", "data": { "currency": "NGN", "amount": "550", "reference": "BUD_1673600359168063493", "status": "success", "message": "Payment successful", "customer": { "email": "customer@email.com" } }}Always verify transactions on your server before fulfilling orders. Never rely solely on client-side callbacks or redirects.
Verification Workflow:
- Receive callback/webhook with transaction reference
- Call Verify API (server-side)
- Check
status === "success" - Verify amount matches expected
- Fulfill order/deliver service
Learn more about verifying transactions.
Testing Your Integration
BudPay provides a comprehensive sandbox environment for testing:
Test Card Numbers:
| Card Type | Number | CVV | Expiry |
|---|---|---|---|
| Visa | 4242424242424242 | 123 | 12/25 |
| Visa (V2) | 4000000000001091 | 484 | 12/29 |
| Mastercard | 5123450000000008 | 100 | 12/25 |
| Verve | 5060990580000217499 | 123 | 12/25 |
Test Mobile Money Numbers:
- Kenya (M-Pesa):
254712345678 - Ghana (MTN):
233244000000
Remember: Always use test credentials in sandbox mode. Switch to live keys only when ready for production.