Payin SDK
Overview
The eLipa Payin SDK provides a simple way to integrate payment collection features into your Nigerian web application. This SDK supports initiating payments, receiving client-side transaction callbacks, and verifying payments from your backend.
✅ Key Capabilities
- Accept NGN payments from customers in Nigeria.
- Use a secure JavaScript interface for payment initiation.
- Handle real-time callback responses after payment.
- Verify completed transactions from your backend.
📘 Versioning
eLipa uses versioning to manage improvements and non-backward-compatible changes.
Currently, there’s no rate limit on incoming requests from your vetted Vendor ID.
Important versioning notes:
- Adding new fields won’t be considered a breaking change.
- Removing or altering existing non-optional fields will be treated as an incompatible change.
- Your system should gracefully handle unexpected additional fields in responses.
🤝 Contributing
We welcome suggestions and feedback!
- 📧 Email: [email protected]
🆘 Need Support?
If you need help or have any questions:
- Contact our team at [email protected]
🔗 Script URLs
Embed the SDK script in your HTML depending on your environment:
<!-- Live -->
<script src="https://sdk.elipa.global/js/elipa-prod-sdk-v2.js"></script>
<!-- Sandbox -->
<script src="https://test.ipayafrica.com/js/elipa-prod-sdk-v2.js"></script>
🧪 Sandbox Testing Guide
Use these credentials to simulate test transactions:
MERCHANT_ID:demovid:demohashKey:ipaykeyBase URL:https://apis.staging.elipa.global
These must not be used in production environments.
🔐 Authentication
All backend interactions require a secure hash. The hash must be generated using HMAC SHA256:
- Sort all fields alphabetically by key.
- Convert them into a URL-encoded string.
- Sign the string using your
hashKey. - Include the resulting
hashas part of your payload.
hashKey in frontend code.Always compute hashes server-side to protect your credentials.
⚙️ Integration Steps
1. Load the SDK
Include the SDK <script> tag in your <head> section.
2. Prepare and Initiate Payment
- HTML
- JavaScript (Postman Pre-request Script)
- Python
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>eLipa Payment</title>
<script src="https://sdk.elipa.global/js/elipa-prod-sdk-v2.js"></script>
</head>
<body>
<button onclick="startElipaPayment()">Pay Now</button>
<script>
function startElipaPayment() {
if (typeof ELIPA === "undefined") {
console.error("Error: eLipa SDK not loaded!");
alert("eLipa SDK failed to load. Check your network.");
return;
}
let paydata = {
MERCHANT_ID: "",// enter your vendor id
vid: "", // enter your vendor id
amount: "10",
order_id: "",
email: "[email protected]",
currency: "NGN",
country: "NG",
callback: function (response) {
if (response.response_code === 200) {
alert("Payment Successful!");
window.location.href = "callback.php";
} else {
alert("Payment Failed: " + response.response_text);
window.location.href = "error.php";
}
}
};
try {
let elipa = new ELIPA(paydata);
console.log("eLipa Object Created:", elipa);
elipa.start(paydata);
} catch (error) {
console.error("eLipa Error:", error.message);
alert("eLipa SDK Error: " + error.message);
}
}
</script>
</body>
</html>
const CryptoJS = require('crypto-js');
const data = {
MERCHANT_ID: '', // enter your vendor id
vid: '', // enter your vendor id
amount: '10',
order_id: '',
email: '[email protected]',
currency: 'NGN',
country: 'NG'
};
const hashKey = 'ipaykey';
const sortedData = Object.keys(data).sort().reduce((obj, key) => {
obj[key] = data[key];
return obj;
}, {});
const queryString = Object.entries(sortedData)
.map(([k, v]) => `${encodeURIComponent(k)}=${encodeURIComponent(v)}`)
.join('&');
const hash = CryptoJS.HmacSHA256(queryString, hashKey).toString(CryptoJS.enc.Hex);
sortedData.hash = hash;
pm.environment.set('elipaSdkPayload', JSON.stringify(sortedData));
import hmac
import hashlib
from urllib.parse import urlencode
sdk_data = {
"MERCHANT_ID": "", #enter your vendor id
"vid": "", # enter your vendor id
"amount": "10",
"order_id": "",
"email": "[email protected]",
"currency": "NGN",
"country": "NG"
}
hash_key = b'ipaykey' # keep secret and never expose in JS
# Sort and encode
sorted_data = dict(sorted(sdk_data.items()))
query_string = urlencode(sorted_data)
# Generate HMAC-SHA256
hash_value = hmac.new(hash_key, query_string.encode(), hashlib.sha256).hexdigest()
# Final SDK config to send to frontend
sdk_data["hash"] = hash_value
# Send sdk_data to the frontend (e.g., via a template engine or API)
🔑 Required Parameters
| Parameter | Description | Required |
|---|---|---|
MERCHANT_ID | Merchant ID from your eLipa dashboard | ✅ |
amount | Amount to be paid (in NGN) | ✅ |
currency | Currency code — use NGN | ✅ |
country | Country code — use ng | ✅ |
email | Payer's email address | ✅ |
order_id | Unique order reference | ✅ |
callback | JavaScript function for handling result | ✅ |
phone | Optional phone number of payer | ❌ |
🧑💻 Steps for the Customer
Step 1: Select Payment Method
After redirect, the customer sees the payment selection screen:

Click BANK TRANSFER to proceed.
Step 2: Complete Bank Transfer

Then, instruct your customer to:
- Open their banking app.
- Select the bank name
- Enter the account number
- Confirm the account name
- Enter the exact amount
- Enter their PIN and authorize the transfer.
- Wait for the SMS confirmation.
Each account is unique and expires in 24 hours. Do not reuse.
📬 Webhook Notification
When a payment is completed, a webhook is sent to your registered Webhook URL which is configure in your merchant dashboard under settings.
| Parameter Name | Description |
|---|---|
| amount | The monetary value of the transaction |
| channel | The channel of payment used to make the transaction |
| channeltype | The type of channel used for the transaction |
| code | The code identifying the transaction |
| commission | The commission charged for the transaction |
| currency | The currency used in the transaction |
| country | The country associated with the transaction |
| datetime | The date and time the transaction was made (YYYY-MM-DD 00:00:00) |
| elipa_reference | A reference number sent by elipa |
| phone | The phone number involved in the transaction |
| reference | A user generated reference number for the transaction |
| status | The current status of the transaction |
| vat | The Value Added Tax (VAT) applied to the transaction |
| vid | The merchant description. Vendor ID (a.k.a Merchant ID) |
🔍 Transaction Search
Endpoint
Search_URL [POST]: https://apis.elipa.global/payments/v2/transaction/search/ng
Parameters and Required Fields
| Parameter Name | Datatype | Description |
|---|---|---|
| oid | alphanumeric(30) | Your unique system generated Order ID |
| vid | alphanumeric(12) | Your vendor ID. Use 'demo' on staging. |
| hash | alphanumeric(64) | HMAC-SHA256 hash of oid + vid using your secret hashKey |
Sample Integration
- PHP
- JavaScript (Postman Pre-request Script)
- Python
<?php
$oid = ''; // from your system
$vid = ''; //your actual vid
$hashKey = 'ipaykey'; //your system generated hash key
$apiUrl = 'https://apis.elipa.global/payments/v2/transaction/search/ng';
$dataString = $oid . $vid;
$hash = hash_hmac('sha256', $dataString, $hashKey);
$payload = [
'oid' => $oid,
'vid' => $vid,
'hash' => $hash
];
$ch = curl_init($apiUrl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($payload));
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Content-Type: application/json'
]);
$response = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
echo "❌ cURL Error: $error
";
} else {
echo "✅ Request Sent to: $apiUrl
";
echo "🔐 Hash Used: $hash
";
echo "📤 Payload: " . json_encode($payload, JSON_PRETTY_PRINT) . "
";
$decoded = json_decode($response, true);
echo "📥 API Response:
" . json_encode($decoded, JSON_PRETTY_PRINT) . "
";
}
?>
const oid = ''; // Your order ID
const vid = ''; // Your vendor ID
const hashKey = ''; // Your hash key
const dataString = oid + vid;
// Generate HMAC SHA256
const hash = CryptoJS.HmacSHA256(dataString, hashKey).toString(CryptoJS.enc.Hex);
// Construct payload
const payload = {
oid: oid,
vid: vid,
hash: hash
};
// Save it to a Postman variable
pm.environment.set("elipaPayload", JSON.stringify(payload));
import hmac
import hashlib
import json
import requests
oid = '' # from your system
vid = '' # your actual vid
hash_key = b'' # your system-generated hash key
data_string = oid + vid
generated_hash = hmac.new(hash_key, data_string.encode(), hashlib.sha256).hexdigest()
payload = {
'oid': oid,
'vid': vid,
'hash': generated_hash
}
url = 'https://apis.elipa.global/payments/v2/transaction/search/ng'
headers = {
'Content-Type': 'application/json'
}
response = requests.post(url, headers=headers, data=json.dumps(payload))
print("Status Code:", response.status_code)
print("Response JSON:")
print(json.dumps(response.json(), indent=2))
Expected Response
- Success
- Not Found
{
"header_status": 200,
"status": 1,
"text": "payment record found",
"data": {
"vid": "demo",
"sid": "mw58demo317071742995052205024694",
"oid": "67e3fe69b0225",
"transaction_amount": "1.00",
"transaction_code": "REF20250326S65864037",
"telephone": "",
"firstname": "First name",
"lastname": "Last name",
"paid_at": "2025-03-26 16:19:44",
"payment_mode": "BANK TRANSFER"
},
"hash": "a23b609d7b7192551a91c6cefec8b25427200d3a4b110ccd243fef1c94218f8b",
"reasonCode": "SUCCESS",
"message": "Transaction has been processed successfully"
}
{
"header_status": 404,
"status": "NOT_FOUND",
"text": "no payment record found"
}
✅ Transaction Verify
Endpoint
Verify_URL [POST]: https://apis.elipa.global/payments/v2/session/v4/transaction/search/ng
Parameters and Required Fields
| Parameter Name | Datatype | Description |
|---|---|---|
| code | alphanumeric(30) | Transaction code received in the webhook |
| vid | alphanumeric(12) | Your vendor ID. Use demo on sn sandbox |
| hash | alphanumeric(64) | HMAC-SHA256 hash of sorted fields using your hashKey |
Sample Integration
- PHP
- JavaScript (Postman Pre-request Script)
- Python
<?php
$fields = [
'code' => '', //The param code that you get on the webhook
'vid' => '', // Your vendor ID
];
ksort($fields);
$data_string = http_build_query($fields);
$hashKey = ''; //your system generated hash key
$fields['hash'] = hash_hmac('sha256', $data_string, $hashKey);
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://apis.elipa.global/payments/v2/session/v4/transaction/search/ng',
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 => json_encode($fields),
CURLOPT_HTTPHEADER => array(
'Content-Type: application/json',
),
));
$response = curl_exec($curl);
curl_close($curl);
echo $response;
const code = 'REPLACE_WITH_CODE'; // from webhook
const vid = 'REPLACE_WITH_YOUR_VENDOR_ID'; // your VID
const hashKey = 'REPLACE_WITH_HASH_KEY'; // your secret hash key
const fields = { code, vid };
// Sort fields alphabetically
const sorted = Object.keys(fields).sort().reduce((acc, key) => {
acc[key] = fields[key];
return acc;
}, {});
// Convert to URL-encoded string
const dataString = new URLSearchParams(sorted).toString();
// Generate HMAC-SHA256 hash
const hash = CryptoJS.HmacSHA256(dataString, hashKey).toString(CryptoJS.enc.Hex);
// Build full payload
sorted.hash = hash;
// Save as environment variable
pm.environment.set('elipaVerifyPayload', JSON.stringify(sorted));
import hmac
import hashlib
import json
import requests
from urllib.parse import urlencode
code = 'REPLACE_WITH_TRANSACTION_CODE'
vid = 'REPLACE_WITH_YOUR_VENDOR_ID'
hash_key = b'REPLACE_WITH_HASH_KEY' # must be bytes
fields = {
'code': code,
'vid': vid
}
# Sort fields and encode
sorted_fields = dict(sorted(fields.items()))
data_string = urlencode(sorted_fields)
# Generate HMAC SHA256 hash
hash_value = hmac.new(hash_key, data_string.encode(), hashlib.sha256).hexdigest()
# Add hash to payload
fields['hash'] = hash_value
url = 'https://apis.elipa.global/payments/v2/session/v4/transaction/search/ng'
headers = { 'Content-Type': 'application/json' }
response = requests.post(url, headers=headers, data=json.dumps(fields))
print("Status Code:", response.status_code)
print("Response:
", json.dumps(response.json(), indent=2))
Expected Response
- Success
- Not Found
{
"header_status": 200,
"status": "SUCCESS",
"text": "payment record found",
"data": {
"paid_at": "2025-07-11 09:33:41",
"firstname": "First name",
"lastname": "Last name",
"telephone": "",
"payment_mode": "BANKTRANSFERNGH",
"curr": "NGN",
"amount": "100.00",
"tid": "JF5191093000E54",
"commission": "1.00",
"oid": "13g85uos"
},
"hash": "eae9e240ba51d54591f29154107ecf19bd828651810dd8634d9bdc182622b295"
}
{
"header_status": 404,
"status": "NOT_FOUND",
"text": "no payment record found"
}
⚠️ Errors & Status Codes
| Code | Meaning | Suggested Action |
|---|---|---|
✅ 200 | OK | Proceed as normal. The request was successful |
⚠️ 400 | Bad Request | Double check your request payload. Check that all required fields are present and are correctly formatted. |
❌ 401 | Unauthorized | Verify API credentials such as vid and hashkey. Also, ensure the hash is correctly computed. |
❓ 404 | Not Found | Ensure transaction identifiers (like oid) are valid. Confirm test data exists if sandboxing. Check for typos or deleted records. |
💥 500 - 5xx | Server Error | Please contact support with logs or payload used when you encounter this. |