Authentication
Sign merchant requests with HMAC-SHA256.
Merchant payment endpoints use HMAC credentials from API keys. Portal management endpoints use a signed-in user's Bearer token instead.
Headers
| Header | Value |
|---|---|
x-api-key | Your TEST or LIVE API key |
x-timestamp | Unix seconds as a decimal string |
x-signature | Lowercase 64-character HMAC-SHA256 hex digest |
Content-Type | application/json for JSON bodies |
Idempotency-Key | Optional for payment creation; not included in the signature |
The timestamp must be within 300 seconds of gateway time, including future timestamps. Keep your server clock synchronized. The API key determines TEST/LIVE; do not add an environment field to payment creation bodies.
Construct the signature
timestamp + "." + rawBodyimport { signRequest } from './vantra-client.mjs';
const timestamp = Math.floor(Date.now() / 1000).toString();
const body = JSON.stringify({ amount: 10000, currency: 'LAK' });
const signature = signRequest({
secret: process.env.VANTRA_API_SECRET,
timestamp,
body,
});
// Send the exact body, timestamp, and signature together.
// gatewayRequest() from the same helper does this for you.Serialize JSON once, sign timestamp + "." + rawBody, and send the same bytes. This preserves the original timestamp.JSON.stringify(body) format for both TEST and LIVE. For a bodyless GET request, sign timestamp + ".". Method, URL/query, and idempotency key are not signed. Use HTTPS in production.
import crypto from 'node:crypto';
function generateSignature(timestamp, body) {
const payload = `${timestamp}.${JSON.stringify(body)}`;
return crypto.createHmac('sha256', process.env.VANTRA_API_SECRET)
.update(payload).digest('hex');
}Preview, copy, or download the server-side request helper. It handles the response envelope and does not automatically retry payments. Reconcile an uncertain payment before creating another. If you use the optional idempotency key, retries keep the original key and body with a fresh timestamp/signature.
Separate secrets
The API secret signs requests to Vantra. Each webhook has a different signing secret for callbacks from Vantra. Never send either secret as a header or include it in client-side JavaScript.