Verso SDK Documentation
Integrate Verso one-time payment links into your platform
The Verso Merchant Payment SDK enables developers to create secure, one-time-use payment links for seamless merchant checkout integration. Users authenticate once, confirm payment details, enter their PIN, and complete transactions without leaving your platform.
Integration Flow
Key Features
Each token is single-use and expires after 24 hours. Tokens are cryptographically random and tied to specific merchants and amounts.
Simple REST API with clear endpoints. Generate a token, open the SDK, and handle the callback. No complex setup required.
Works on desktop and mobile. Open SDK in a new window or embed in an iframe for seamless checkout experience.
Getting Started
Follow these steps to integrate the Verso SDK into your application.
Prerequisites
- A Verso merchant account with API credentials
- Authentication token from your merchant dashboard
- Basic knowledge of HTTP requests and JavaScript
Step 1: Get Your Credentials
Log in to your Verso merchant dashboard and navigate to:
Developer Settings → API Keys
You'll find your authToken. Keep this secure and never expose it in client-side code.
Step 2: Test Your Setup
Use the Sandbox / Test panel to verify your credentials work correctly.
Step 3: Integrate into Your App
See the Integration Guide for step-by-step implementation instructions with code examples.
Authentication
All API requests require an authentication token to identify your merchant account.
How to Obtain an Auth Token
- Log in to your Verso merchant portal
- Navigate to Developer Settings → API Keys
- Copy your API token (it's a long, cryptographic string)
- Use this token in the
tokenparameter when calling the generate endpoint
Token Security
Token Rotation
For security, rotate your API tokens regularly. You can generate new tokens and revoke old ones from your merchant dashboard.
Example: Using Your Token
curl --location 'http://localhost:3000/api/sdk-access/generate' \
--header 'Content-Type: application/json' \
--data '{
"token": "your_auth_token_here",
"amount": 500
}'
API Reference
Complete documentation of Verso SDK API endpoints.
Generate Payment Token
Description
Generate a one-time-use payment link token. Call this from your backend server with your authentication token.
Request Body
{
"token": "your_merchant_auth_token",
"amount": 500
}
| Parameter | Type | Description |
|---|---|---|
token |
string | Your merchant authentication token from the API dashboard |
amount |
number | Payment amount in CFA. Must be greater than 0 |
Response
{
"success": true,
"token": "a1b2c3d4e5f6...",
"merchantId": "6982c6da5ee026485586c3b0",
"userId": "68d0d522ca4fdef054351beb",
"amount": 500,
"sdkUrl": "http://localhost:3000/verso-merchant-sdk.html?token=a1b2c3d4&merchantId=6982c6d&amount=500",
"message": "Payment link generated successfully"
}
Validate Payment Token
Description
Validate a payment token and mark it as used. Called automatically by the SDK frontend, but documented here for reference.
Query Parameters
?token=TOKEN&merchantId=MERCHANT_ID&amount=AMOUNT
| Parameter | Type | Description |
|---|---|---|
token |
string | The SDK token generated by the generate endpoint |
merchantId |
string | The merchant ID from the token response |
amount |
number | The payment amount from the token response |
Response
{
"success": true,
"message": "Payment link validated successfully",
"token": "a1b2c3d4e5f6...",
"merchantId": "6982c6da5ee026485586c3b0",
"amount": 500,
"merchantCompanyName": "Test Enterprise"
}
Notify Payment (Webhook Trigger)
Description
Called automatically by the SDK after a successful payment. Looks up the merchant's registered webhook URL and fires a payment.success notification. If no webhook is configured the call succeeds silently.
This endpoint is called internally — you do not need to call it yourself. It is documented here for transparency.
Request Body
{
"token": "sdk_access_token_here",
"transactionId": "2066618466",
"amount": 5000,
"merchantId": "6982c6da5ee026485586c3b0",
"customerName": "Jean Dupont",
"customerEmail": "jean@example.com"
}
| Parameter | Type | Required | Description |
|---|---|---|---|
token | string | Yes | The one-time SDK access token |
transactionId | string | Yes | Transaction ID from the payment API |
amount | number | Yes | Payment amount |
merchantId | string | Yes | Target merchant ID |
customerName | string | No | Name of the paying user |
customerEmail | string | No | Email of the paying user |
Response
// Webhook delivered
{ "success": true, "webhookFired": true, "webhookStatus": 200 }
// No webhook registered (not an error)
{ "success": true, "webhookFired": false, "message": "No active webhook registered" }
// Delivery failed (endpoint unreachable — not an error for the caller)
{ "success": true, "webhookFired": false, "message": "Webhook delivery failed: ..." }
Integration Guide
Step-by-step instructions to integrate the Verso SDK into your application.
Step 1: Backend Setup
Create an endpoint in your backend that calls the Verso generate API. This endpoint should:
- Accept the payment amount from your frontend
- Use your secure auth token (stored in environment variables)
- Call POST
/api/sdk-access/generate - Return the
sdkUrlto your frontend
Example: Node.js/Express
app.post('/api/generate-payment-link', async (req, res) => {
const { amount } = req.body;
try {
const response = await fetch('http://localhost:3000/api/sdk-access/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
token: process.env.VERSO_AUTH_TOKEN,
amount: amount
})
});
const data = await response.json();
if (!data.success) throw new Error(data.error);
res.json({
success: true,
sdkUrl: data.sdkUrl,
token: data.token
});
} catch (error) {
res.status(500).json({ success: false, error: error.message });
}
});
Step 2: Frontend Integration
Create a button or form that triggers the SDK window.
Example: Open SDK in New Window
async function initiatePayment(amount) {
try {
// Get SDK URL from your backend
const response = await fetch('/api/generate-payment-link', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ amount: amount })
});
const data = await response.json();
if (!data.success) throw new Error(data.error);
// Open SDK in new window
const width = 500;
const height = 700;
const left = (screen.width - width) / 2;
const top = (screen.height - height) / 2;
window.open(
data.sdkUrl,
'verso-payment',
`width=${width},height=${height},left=${left},top=${top}`
);
// Listen for success message from SDK
window.addEventListener('message', handleSDKMessage);
} catch (error) {
console.error('Error initiating payment:', error);
}
}
function handleSDKMessage(event) {
if (event.data.type === 'payment-success') {
console.log('Payment successful!', event.data.transactionId);
// Handle success - update UI, save transaction ID, etc.
}
}
Step 3: Handle Payment Success
After the user completes payment in the SDK, your server is notified automatically via webhook (if you've registered a URL). You can also:
- Listen for window messages from the SDK popup
- Register a webhook URL via
POST /api/merchant/webhook-registerto receive apayment.successPOST on your server - Update your order/cart status to "completed" when the webhook arrives
Code Samples
Copy-paste ready examples for common integration scenarios.
cURL - Generate Token
curl --location 'http://localhost:3000/api/sdk-access/generate' \
--header 'Content-Type: application/json' \
--data '{
"token": "your_auth_token_here",
"amount": 500
}'
Node.js - Generate Token
const fetch = require('node-fetch');
async function generatePaymentToken(authToken, amount) {
const response = await fetch('http://localhost:3000/api/sdk-access/generate', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
token: authToken,
amount: amount
})
});
const data = await response.json();
return data;
}
// Usage
generatePaymentToken('your_token', 500)
.then(result => console.log('SDK URL:', result.sdkUrl))
.catch(err => console.error('Error:', err.message));
JavaScript - Handle Payment Completion
// Open SDK and listen for completion
function handlePaymentCompletion() {
window.addEventListener('message', (event) => {
if (event.origin !== 'http://localhost:3000') return;
if (event.data.type === 'payment-complete') {
console.log('Transaction ID:', event.data.transactionId);
console.log('Amount:', event.data.amount);
// Update UI or redirect user
alert('Payment successful! Transaction: ' + event.data.transactionId);
}
});
}
Python - Generate Token
import requests
import json
def generate_payment_token(auth_token, amount):
url = 'http://localhost:3000/api/sdk-access/generate'
headers = {'Content-Type': 'application/json'}
payload = {
'token': auth_token,
'amount': amount
}
response = requests.post(url, headers=headers, json=payload)
return response.json()
# Usage
result = generate_payment_token('your_token', 500)
print(f"SDK URL: {result['sdkUrl']}")
Webhooks & Callbacks
Receive real-time payment notifications on your server
Webhooks allow Verso to send your server real-time HTTP callbacks when a payment succeeds. Instead of polling for status, your endpoint is called automatically the moment a transaction completes.
Supported Events
| Event Type | Trigger | Description |
|---|---|---|
payment.success |
After PIN confirmation | Payment was processed successfully and transaction ID is confirmed |
Webhook Payload
Webhooks are delivered as POST requests with a JSON body:
{
"event": "payment.success",
"timestamp": "2026-07-29T21:15:54.959Z",
"data": {
"transactionId": "2066618466",
"amount": 5000,
"currency": "XAF",
"status": "success",
"merchantId": "6982c6da5ee026485586c3b0",
"customerName": "Jean Dupont",
"customerEmail": "jean@example.com",
"sdkToken": "a1b2c3d4e5f6g7h8..."
}
}
Payload Fields
| Field | Type | Description |
|---|---|---|
event | string | Always payment.success |
timestamp | ISO 8601 | UTC time the notification was sent |
data.transactionId | string | Verso transaction ID |
data.amount | number | Amount paid in XAF |
data.currency | string | Always XAF |
data.status | string | Always success |
data.merchantId | string | Your merchant ID |
data.customerName | string | null | Full name of the paying user |
data.customerEmail | string | null | Email of the paying user |
data.sdkToken | string | Truncated SDK token (first 16 chars + …) |
Request Headers
{
"Content-Type": "application/json",
"X-Verso-Event": "payment.success",
"X-Verso-Signature": "<hmac-sha256-hex>"
}
The X-Verso-Signature is an HMAC-SHA256 hex digest of the full JSON payload, keyed with your SDK token. Use it to verify the request is genuinely from Verso.
Registering Your Webhook URL
Register your endpoint directly via the API — no need to contact support.
curl -X POST https://your-verso-host/api/merchant/webhook-register \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <merchant_token>" \
-d '{ "webhookUrl": "https://yourapp.com/webhooks/verso" }'
You can also test your URL first (and save it only if the test succeeds) using:
curl -X POST https://your-verso-host/api/merchant/webhook-test-and-save \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <merchant_token>" \
-d '{ "webhookUrl": "https://yourapp.com/webhooks/verso" }'
Setup Checklist
- Create your handler endpoint — an HTTPS route that accepts POST requests
- Register the URL — call
POST /api/merchant/webhook-registerwith your URL - Verify the signature — compute HMAC-SHA256 on the raw body and compare with
X-Verso-Signature - Return HTTP 200 — respond promptly; Verso does not retry failed deliveries
Signature Verification
Recompute the HMAC using the raw request body and your SDK token as the key, then compare with the header value.
Node.js / Express
const crypto = require('crypto');
app.post('/webhooks/verso', express.json(), (req, res) => {
const signature = req.headers['x-verso-signature'];
const payload = req.body;
// Re-compute expected signature using your SDK token as the HMAC key
const expected = crypto
.createHmac('sha256', process.env.VERSO_SDK_TOKEN)
.update(JSON.stringify(payload))
.digest('hex');
if (expected !== signature) {
return res.status(401).send('Invalid signature');
}
if (payload.event === 'payment.success') {
const { transactionId, amount, customerName } = payload.data;
console.log(`Payment received: ${transactionId} — ${amount} XAF from ${customerName}`);
// Update your order status, notify customer, etc.
}
res.sendStatus(200);
});
Python / Flask
import hmac, hashlib, json, os
from flask import Flask, request
app = Flask(__name__)
@app.route('/webhooks/verso', methods=['POST'])
def verso_webhook():
signature = request.headers.get('X-Verso-Signature', '')
payload_raw = request.get_data() # raw bytes — important!
payload = request.get_json()
expected = hmac.new(
os.environ['VERSO_SDK_TOKEN'].encode(),
payload_raw,
hashlib.sha256
).hexdigest()
if not hmac.compare_digest(expected, signature):
return 'Invalid signature', 401
if payload['event'] == 'payment.success':
data = payload['data']
print(f"Payment {data['transactionId']} — {data['amount']} XAF")
return {'status': 'ok'}, 200
Testing Webhooks Locally
Use a tunneling service like ngrok to expose your local server:
# Terminal 1: Start your local server
npm start
# Terminal 2: Expose it publicly
ngrok http 3000
# Register the public URL
curl -X POST http://localhost:3000/api/merchant/webhook-register \
-H "Content-Type: application/json" \
-H "Authorization: Bearer <your_merchant_token>" \
-d '{ "webhookUrl": "https://1234-56-78-90-12.ngrok-free.app/webhooks/verso" }'
Best Practices
- ✅ Use HTTPS — always register an
https://URL in production - ✅ Verify the signature — reject requests with a mismatched or missing
X-Verso-Signature - ✅ Respond quickly — return HTTP 200 immediately; run heavy processing asynchronously
- ✅ Deduplicate by transactionId — store received IDs to avoid processing the same payment twice if you re-register and trigger a test
- ✅ Log everything — keep webhook logs for auditing and debugging
- ❌ Don't block on external calls — avoid slow DB writes or third-party API calls in the handler's critical path
Common Issues
- Check
GET /api/merchant/webhookto confirm your URL is registered andactive: true - Verify your server is reachable from the internet (use
webhook-test-and-saveto test) - Ensure your handler returns HTTP 200, not a redirect or error
- Use the raw request body bytes — do not parse to JSON before hashing
- Confirm you're using the correct SDK token as the HMAC key
Error Reference
Common errors and how to resolve them.
Generate Token Errors
| Error Code | HTTP Status | Meaning | Solution |
|---|---|---|---|
Invalid or missing auth token |
400 | The token parameter is missing or not a string |
Ensure you're passing a valid auth token in the request body |
Invalid auth token |
401 | The token doesn't match any user in the database | Check that the token is correct. Tokens are case-sensitive |
No merchant account found |
404 | The user exists but has no associated merchant account | Set up a merchant account in the merchant dashboard |
Invalid amount |
400 | Amount is missing, not a number, or ≤ 0 | Ensure amount is a positive number (e.g., 500 for 500 CFA) |
Token Validation Errors
| Error Code | Meaning | Solution |
|---|---|---|
TOKEN_NOT_FOUND |
Token doesn't exist or parameters don't match | Verify token, merchantId, and amount are correct. Generate a new token |
TOKEN_ALREADY_USED |
Token has already been used | Tokens are single-use. Generate a new token for another payment |
NO_TOKEN |
SDK accessed without a token parameter | Always generate a token first and pass it in the URL |
Payment Errors
| Error | Meaning | Solution |
|---|---|---|
Invalid or expired auth token |
User token in login request is invalid | User should log in again with correct credentials |
Code PIN incorrect |
User entered wrong PIN | User can retry PIN entry |
HTTP 422 |
Payment request validation failed | Check merchantId exists and amount is valid |
Debugging Tips
Open browser console (F12) and check the Network tab to see all API requests and responses. Look for request/response bodies to identify parameter issues.
Double-check your auth token in the dashboard. Tokens are long and case-sensitive. Never copy extra spaces.
Generated tokens expire after 24 hours. If you see TOKEN_NOT_FOUND, generate a fresh token.
Sandbox / Test Panel
Test the API without writing code. Generate tokens, view responses, and try the SDK flow.
Generate Test Token
Found in: Merchant Dashboard → Developer Settings → API Keys
1. Paste your auth token above
2. Enter a test amount
3. Click "Generate Token"
4. Review the API response
5. Click "Open SDK Window" to test the full flow