Welcome to Fundsvera API
Fundsvera provides a comprehensive suite of payment and virtual account payment collections & bank transafer API. Our infrastructure enables businesses to accept payments, create, manage, and monitor virtual accounts seamlessly.
Free API Integration Support! 🎉
We offer FREE integration assistance to help you get started quickly. Our team of experts is ready to help you integrate our APIs seamlessly.
Contact Our Integration TeamCore Features
- Payment collections
- Virtual account creation for customers
- Real-time transaction monitoring
- Webhook notifications for events
- Secure authentication with API keys
- Comprehensive transaction history
https://fundsvera.co/api/v1
Authentication
All API requests require authentication using your API keys in the request headers.
API Credentials
After business onboarding, you will receive:
- Public Key - Your business public identifier
- Secret Key - Your private authentication key (keep secret!)
Required Headers
| Header | Format | Required | Description |
|---|---|---|---|
Authorization |
Bearer {secret_key} |
Yes | Your business secret key |
Public-Key |
{public_key} |
Yes | Your business public key |
Content-Type |
application/json |
Yes | Request body format |
Virtual Account (Create)
Create a virtual bank account for a customer. If an account already exists, it will be returned instead of creating a duplicate.
Request Parameters
| Parameter | Type | Required | Validation | Description |
|---|---|---|---|---|
email |
string | Yes | Valid email format | Customer's email address |
name |
string | Yes | Alphanumeric, spaces, dashes | Customer's name |
bank_code |
string | Yes | Must be "100033" | Bank code (currently Palmpay) |
phone |
string | Yes | Exactly 11 digits | Customer's phone number |
Example Request
{
"email": "[email protected]",
"name": "Bolaji Olami",
"bank_code": "100033",
"phone": "08012345678"
}
Success Response (200 OK)
{
"status": "SUCCESS",
"message": "Virtual account number is now created and activated",
"customer": {
"customer_email": "[email protected]",
"customer_phone": "08012345678",
"customer_name": "Bolaji Olami"
},
"virtual_account": {
"bank_name": "Palmpay",
"account_name": "Fundsvera - Bol Fv",
"account_number": "1234567890",
"bank_code": "100033",
"account_status": "Active"
},
"business": {
"business_name": "Your Business Name",
"business_email": "[email protected]"
}
}
Initiate Bank Transfer (Secured Checkout)
Create a time‑limited virtual bank account and a secured checkout URL for a customer to complete a bank transfer payment. The account details are valid for 30 minutes.
Request Parameters
| Parameter | Type | Required | Validation | Description |
|---|---|---|---|---|
customer_email |
string | Yes | Valid email address | Customer's email |
customer_name |
string | Yes | Alphanumeric, spaces, dashes, underscores | Customer's full name |
amount |
number | Yes | ≥ 100 (NGN) | Amount to be paid |
request_id |
string | Yes | Minimum 20 characters, unique per business | Your unique transaction reference |
redirect_url |
string | Yes | Must start with http or https, no query parameters |
Where we redirect your customer to after the payment |
customer_phone |
string | Optional | Exactly 11 digits | Customer's phone number |
Example Request
{
"customer_email": "[email protected]",
"customer_name": "Bolaji Ola",
"amount": 5000,
"request_id": "unique-ref-1234567890abcdefghijk",
"redirect_url": "https://your-website.com/success-page",
"customer_phone": "08012345678"
}
Success Response (200 OK)
{
"status": "Pending",
"message": "Account details generated successfully",
"customer_email": "[email protected]",
"customer_name": "Bolaji Ola",
"bank_name": "Bank Name",
"account_name": "Fundsvera / Merchant Name",
"account_number": "1234567890",
"validity": "30 minutes",
"request_id": "unique-ref-1234567890abcdefghijk",
"trx_ref": "Tref...",
"checkout_url": "https://fundsvera.co/secured-checkout/?ref=...&sig=...&D=...",
"business_name": "Your Business Name",
"business_email": "[email protected]"
}
The checkout_url is a unique, signed link that you can redirect your customer to. It displays payment instructions and an auto‑expiry timer.
Error Responses
| HTTP Status | Error Message |
|---|---|
| 400 | Please input valid customer email |
| 400 | Please input valid customer name |
| 400 | Please input valid amount greater than or equal to 100 |
| 400 | Duplicate request ID, please use a unique request ID |
| 401 | Unauthorized request please use valid keys |
| 500 | System busy please try again later |
Webhook Security
Fundsvera signs all webhook payloads with an HMAC‑SHA256 signature using your business secret key (the same key used for API authentication). The signature is sent in the X-FUNDSVERA-SIGNATURE header.
How to Verify
On your webhook endpoint, recalculate the HMAC‑SHA256 of the raw request body using your secret key and compare it (timing‑safe) with the X-FUNDSVERA-SIGNATURE header. If they match, the webhook is genuine.
Always return HTTP 200 after processing the webhook to acknowledge receipt. If you return any other status, Fundsvera may retry the delivery.
Verification Code Examples
<?php
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_FUNDSVERA_SIGNATURE'] ?? '';
$secret = 'YOUR_SECRET_KEY'; // Business secret key
$computed = hash_hmac('sha256', $payload, $secret);
if (hash_equals($computed, $signature)) {
// Trusted – process the webhook
http_response_code(200);
echo json_encode(['status' => 'received']);
} else {
http_response_code(401);
echo json_encode(['error' => 'Invalid signature']);
exit;
}
?>
const crypto = require('crypto');
function verify(payload, signature, secret) {
const computed = crypto
.createHmac('sha256', secret)
.update(payload)
.digest('hex');
return crypto.timingSafeEqual(Buffer.from(computed), Buffer.from(signature));
}
app.post('/webhook', (req, res) => {
const payload = JSON.stringify(req.body);
const signature = req.headers['x-fundsvera-signature'];
if (!verify(payload, signature, 'YOUR_SECRET_KEY')) {
return res.status(401).json({ error: 'Invalid signature' });
}
// Process event...
res.status(200).json({ status: 'received' });
});
import hmac, hashlib
def verify(payload, signature, secret):
computed = hmac.new(secret.encode(), payload.encode(), hashlib.sha256).hexdigest()
return hmac.compare_digest(computed, signature)
@app.route('/webhook', methods=['POST'])
def webhook():
payload = request.get_data(as_text=True)
signature = request.headers.get('X-FUNDSVERA-SIGNATURE', '')
if not verify(payload, signature, 'YOUR_SECRET_KEY'):
return jsonify({'error': 'Invalid signature'}), 401
# Process event...
return jsonify({'status': 'received'}), 200
Bank Transfer Webhook
When a bank transfer is successfully received, Fundsvera sends a bank_transfer.completed event to the webhook URL configured in your business profile. You must return HTTP 200 after processing to acknowledge receipt.
Webhook Payload Example
{
"status": "SUCCESS",
"transaction_status": "SUCCESSFUL",
"trx_ref": "Btrf...",
"request_id": "unique-ref-1234567890abcdefghijk",
"amount_paid": 5000,
"settlement_amount": 4875,
"fee": 125,
"trx_type": "checkout",
"payer": {
"name": "Bolaji Ola",
"account_no": "1234567890",
"bank_name": "Bank Name"
},
"customer": {
"email": "[email protected]",
"name": "Bolaji Ola",
"virtual_account_no": "1234567890",
"bank_name": "Palmpay",
"phone": "08012345678"
},
"message": "Your payment has been successfully processed.",
"created_date": "2026-06-04T10:30:00Z"
}
Webhook Handler Code
<?php
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_FUNDSVERA_SIGNATURE'] ?? '';
$secret = 'YOUR_SECRET_KEY'; // Business secret key
$computed = hash_hmac('sha256', $payload, $secret);
if (!hash_equals($computed, $signature)) {
http_response_code(401);
echo json_encode(['error' => 'Invalid signature']);
exit;
}
$data = json_decode($payload, true);
if ($data['transaction_status'] === 'SUCCESSFUL') {
$trx = $data;
// Validate request_id against your database
// Update order status to paid
// Grant value to customer
error_log("Bank transfer completed: {$trx['trx_ref']} for {$trx['amount_paid']}");
http_response_code(200);
echo json_encode(['status' => 'received']);
} else {
http_response_code(200);
echo json_encode(['status' => 'ignored']);
}
?>
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
const SECRET = 'YOUR_SECRET_KEY';
function verify(payload, signature) {
const computed = crypto.createHmac('sha256', SECRET).update(payload).digest('hex');
return crypto.timingSafeEqual(Buffer.from(computed), Buffer.from(signature));
}
app.post('/webhook', (req, res) => {
const payload = JSON.stringify(req.body);
const signature = req.headers['x-fundsvera-signature'];
if (!verify(payload, signature)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = req.body;
if (event.transaction_status === 'SUCCESSFUL') {
const { trx_ref, request_id, amount_paid, customer } = event;
console.log(`✅ Payment: ${amount_paid} for ${customer.email}`);
// Update database, grant access, etc.
return res.status(200).json({ status: 'received' });
}
res.status(200).json({ status: 'ignored' });
});
app.listen(3000);
from flask import Flask, request, jsonify
import hmac, hashlib
app = Flask(__name__)
SECRET = 'YOUR_SECRET_KEY'
def verify(payload, signature):
computed = hmac.new(SECRET.encode(), payload.encode(), hashlib.sha256).hexdigest()
return hmac.compare_digest(computed, signature)
@app.route('/webhook', methods=['POST'])
def webhook():
payload = request.get_data(as_text=True)
signature = request.headers.get('X-FUNDSVERA-SIGNATURE', '')
if not verify(payload, signature):
return jsonify({'error': 'Invalid signature'}), 401
data = request.get_json()
if data.get('transaction_status') == 'SUCCESSFUL':
print(f"Payment received: {data['amount_paid']} from {data['customer']['email']}")
# Update your database
return jsonify({'status': 'received'}), 200
return jsonify({'status': 'ignored'}), 200
if __name__ == '__main__':
app.run(port=3000)
Virtual Account Webhook
When a virtual account receives a payment, Fundsvera sends an event to your webhook URL configured in your business profile. Always return HTTP 200 after successful processing.
Payment Received Webhook (Example)
{
"status": "SUCCESS",
"transaction_status": "SUCCESSFUL",
"trx_ref": "Tref...",
"amount_paid": 5000,
"settlement_amount": 4875,
"fee": 125,
"payer": {
"name": "Sender Name",
"account_no": "9876543210",
"bank_name": "Sender Bank"
},
"customer": {
"email": "[email protected]",
"virtual_account_no": "1234567890",
"bank_name": "Palmpay",
"phone": "08012345678"
},
"message": "Your payment has been successfully processed.",
"created_date": "2026-06-04T10:30:00Z"
}
Webhook Handler Code
<?php
$payload = file_get_contents('php://input');
$signature = $_SERVER['HTTP_X_FUNDSVERA_SIGNATURE'] ?? '';
$secret = 'YOUR_SECRET_KEY';
$computed = hash_hmac('sha256', $payload, $secret);
if (!hash_equals($computed, $signature)) {
http_response_code(401);
echo json_encode(['error' => 'Invalid signature']);
exit;
}
$data = json_decode($payload, true);
if ($data['transaction_status'] === 'SUCCESSFUL') {
// Handle successful payment to a virtual account
$va = $data['customer']['virtual_account_no'];
$amount = $data['amount_paid'];
error_log("Virtual account {$va} funded with {$amount}");
http_response_code(200);
echo json_encode(['status' => 'received']);
} else {
http_response_code(200);
echo json_encode(['status' => 'ignored']);
}
?>
const express = require('express');
const crypto = require('crypto');
const app = express();
app.use(express.json());
const SECRET = 'YOUR_SECRET_KEY';
function verify(payload, signature) {
const computed = crypto.createHmac('sha256', SECRET).update(payload).digest('hex');
return crypto.timingSafeEqual(Buffer.from(computed), Buffer.from(signature));
}
app.post('/webhook', (req, res) => {
const payload = JSON.stringify(req.body);
const signature = req.headers['x-fundsvera-signature'];
if (!verify(payload, signature)) {
return res.status(401).json({ error: 'Invalid signature' });
}
const event = req.body;
if (event.transaction_status === 'SUCCESSFUL') {
const { virtual_account_no } = event.customer;
console.log(`Virtual account ${virtual_account_no} credited with ${event.amount_paid}`);
return res.status(200).json({ status: 'received' });
}
res.status(200).json({ status: 'ignored' });
});
app.listen(3000);
from flask import Flask, request, jsonify
import hmac, hashlib
app = Flask(__name__)
SECRET = 'YOUR_SECRET_KEY'
def verify(payload, signature):
computed = hmac.new(SECRET.encode(), payload.encode(), hashlib.sha256).hexdigest()
return hmac.compare_digest(computed, signature)
@app.route('/webhook', methods=['POST'])
def webhook():
payload = request.get_data(as_text=True)
signature = request.headers.get('X-FUNDSVERA-SIGNATURE', '')
if not verify(payload, signature):
return jsonify({'error': 'Invalid signature'}), 401
data = request.get_json()
if data.get('transaction_status') == 'SUCCESSFUL':
va = data['customer']['virtual_account_no']
print(f"Virtual account {va} funded with {data['amount_paid']}")
return jsonify({'status': 'received'}), 200
return jsonify({'status': 'ignored'}), 200
if __name__ == '__main__':
app.run(port=3000)
Code Samples
Ready-to-use code examples for integrating with Fundsvera API.
Free Integration Support
Can't figure out the integration? Our team will help you for FREE!
Schedule Free Integration HelpCreate Virtual Account
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => 'https://fundsvera.co/api/v1/create-virtual-account',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer YOUR_SECRET_KEY',
'Public-Key: YOUR_PUBLIC_KEY',
'Content-Type: application/json'
],
CURLOPT_POSTFIELDS => json_encode([
'email' => '[email protected]',
'name' => 'Bolaji Olami',
'bank_code' => '100033',
'phone' => '08012345678'
])
]);
$response = curl_exec($curl);
curl_close($curl);
?>
const axios = require('axios');
async function createVA() {
const res = await axios.post(
'https://fundsvera.co/api/v1/create-virtual-account',
{
email: '[email protected]',
name: 'Bolaji Olami',
bank_code: '100033',
phone: '08012345678'
},
{
headers: {
'Authorization': 'Bearer YOUR_SECRET_KEY',
'Public-Key': 'YOUR_PUBLIC_KEY',
'Content-Type': 'application/json'
}
}
);
console.log(res.data);
}
createVA();
import requests
url = "https://fundsvera.co/api/v1/create-virtual-account"
headers = {
"Authorization": "Bearer YOUR_SECRET_KEY",
"Public-Key": "YOUR_PUBLIC_KEY",
"Content-Type": "application/json"
}
payload = {
"email": "[email protected]",
"name": "Bolaji Olami",
"bank_code": "100033",
"phone": "08012345678"
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
curl -X POST https://fundsvera.co/api/v1/create-virtual-account \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Public-Key: YOUR_PUBLIC_KEY" \
-H "Content-Type: application/json" \
-d '{
"email": "[email protected]",
"name": "Bolaji Olami",
"bank_code": "100033",
"phone": "08012345678"
}'
Initiate Bank Transfer
<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => 'https://fundsvera.co/api/v1/secured-checkout',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_POST => true,
CURLOPT_HTTPHEADER => [
'Authorization: Bearer YOUR_SECRET_KEY',
'Public-Key: YOUR_PUBLIC_KEY',
'Content-Type: application/json'
],
CURLOPT_POSTFIELDS => json_encode([
'customer_email' => '[email protected]',
'customer_name' => 'Bolaji Ola',
'amount' => 5000,
'request_id' => 'unique-ref-1234567890abcdefghijk',
'redirect_url' => 'https://your-website.com/sucess-page'
])
]);
$response = curl_exec($curl);
curl_close($curl);
?>
const axios = require('axios');
async function initBankTransfer() {
const res = await axios.post(
'https://fundsvera.co/api/v1/secured-checkout',
{
customer_email: '[email protected]',
customer_name: 'Bolaji Ola',
amount: 5000,
request_id: 'unique-ref-1234567890abcdefghijk',
redirect_url: 'https://your-website.com/sucess-page'
},
{
headers: {
'Authorization': 'Bearer YOUR_SECRET_KEY',
'Public-Key': 'YOUR_PUBLIC_KEY',
'Content-Type': 'application/json'
}
}
);
console.log(res.data);
}
initBankTransfer();
import requests
url = "https://fundsvera.co/api/v1/secured-checkout"
headers = {
"Authorization": "Bearer YOUR_SECRET_KEY",
"Public-Key": "YOUR_PUBLIC_KEY",
"Content-Type": "application/json"
}
payload = {
"customer_email": "[email protected]",
"customer_name": "Bolaji Ola",
"amount": 5000,
"request_id": "unique-ref-1234567890abcdefghijk",
"redirect_url": "https://your-website.com/sucess-page"
}
response = requests.post(url, json=payload, headers=headers)
print(response.json())
curl -X POST https://fundsvera.co/api/v1/secured-checkout \
-H "Authorization: Bearer YOUR_SECRET_KEY" \
-H "Public-Key: YOUR_PUBLIC_KEY" \
-H "Content-Type: application/json" \
-d '{
"customer_email": "[email protected]",
"customer_name": "Bolaji Ola",
"amount": 5000,
"request_id": "unique-ref-1234567890abcdefghijk",
"redirect_url": "https://your-website.com/sucess-page"
}'
Coming Soon
Upcoming Features
- 📊 Transaction History - Retrieve detailed transaction history
- 💰 Balance Inquiry - Check virtual account balances
- 🔄 Bulk Operations - Create multiple accounts at once
- 📱 USSD Integration - USSD payment capabilities
- 📈 Analytics & Reporting - Advanced analytics dashboard
Error Codes
HTTP Status Codes
| Status | Code | Description |
|---|---|---|
| 200 | OK | Request successful |
| 400 | Bad Request | Invalid parameters |
| 401 | Unauthorized | Invalid API keys |
| 403 | Forbidden | Insufficient permissions |
| 404 | Not Found | Resource not found |
| 500 | Server Error | Internal server issue |
Still having issues?
Our support team is available 24/7 to help you resolve any errors.
Get Free Support