Developer API
Authentication and request signing
The three headers on every request, how the gateway checks the client, the IP, the timestamp and the nonce, how to sign a POST, PUT or PATCH payload, and the exact error responses.
Updated 20 September 2026
Every request to the external API carries authentication headers, and every request that changes data carries a signature as well. This page gives the exact rules; the credentials themselves are issued when your integration is set up.
The checks, in order
- The client ID is looked up. An unknown or inactive client ID is answered with 401.
- The calling IP address is compared with the addresses allowed for the integration. An address not on the list is answered with 403.
- The timestamp must be within five minutes of the server’s clock, and the nonce must not have been used before. An expired timestamp or a reused nonce is answered with 401.
- For POST, PUT and PATCH, the gateway recomputes the signature of the payload with your client secret. A mismatch is answered with 401.
Only then is the request processed.
Request headers
x-client-id: the client ID issued to your application, for exampleveda_pub_a935d5f172268cdf122572defcc2631b.x-nonce: a random string generated fresh for every request, for example2346301255735. It is what stops a captured request from being replayed.x-timestamp: the current UTC time in milliseconds when the request is sent, for example1696301254321.
A GET request needs nothing more:
curl -X GET "https://<your-base-url>/api/v1/external/products" \
-H "x-client-id: veda_pub_a935d5f172268cdf122572defcc2631b" \
-H "x-nonce: 2346301255735" \
-H "x-timestamp: 1696301254321"
Signing a request that changes data
For POST, PUT and PATCH, the JSON payload itself carries a signature that proves it was not altered and came from you.
- Add
nonce(a unique random string) andtimestamp(the current Unix time in milliseconds, as an integer) to the JSON payload. - Stringify the complete payload and Base64-encode the string.
- Compute HMAC-SHA256 over the Base64 string, using your client secret as the key.
- Put the resulting hexadecimal string in a
signaturefield inside the payload.
In Node.js:
const crypto = require('crypto');
function prepareSignedPayload(payload, clientSecret) {
payload.timestamp = Date.now();
payload.nonce = crypto.randomUUID();
const base64Payload = Buffer.from(JSON.stringify(payload)).toString('base64');
payload.signature = crypto.createHmac('sha256', clientSecret).update(base64Payload).digest('hex');
return payload;
}
The request headers are still required on signed requests.
Authentication errors
Missing or invalid client ID, 401:
{ "success": false, "status": 401, "message": "Invalid or inactive Client ID or API Key." }
Missing header, 401:
{ "success": false, "status": 401, "message": "Request timestamp (x-timestamp) is missing." }
Expired timestamp, 401:
{ "success": false, "status": 401, "message": "Request timestamp expired or invalid." }
Reused nonce, 401:
{
"success": false,
"status": 401,
"message": "Replay attack detected: Request nonce already used."
}
IP address not allowed, 403:
{ "success": false, "status": 403, "message": "Access denied from IP address: 203.0.113.99" }