Skip to content

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

  1. The client ID is looked up. An unknown or inactive client ID is answered with 401.
  2. The calling IP address is compared with the addresses allowed for the integration. An address not on the list is answered with 403.
  3. 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.
  4. 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 example veda_pub_a935d5f172268cdf122572defcc2631b.
  • x-nonce: a random string generated fresh for every request, for example 2346301255735. It is what stops a captured request from being replayed.
  • x-timestamp: the current UTC time in milliseconds when the request is sent, for example 1696301254321.

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.

  1. Add nonce (a unique random string) and timestamp (the current Unix time in milliseconds, as an integer) to the JSON payload.
  2. Stringify the complete payload and Base64-encode the string.
  3. Compute HMAC-SHA256 over the Base64 string, using your client secret as the key.
  4. Put the resulting hexadecimal string in a signature field 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" }

Free consultation

Get a free 30‑minute setup consultation

A Kuver Books specialist in Kathmandu walks through billing, inventory and VAT for your exact business. No commitment, no sales pitch.

No spam. A real person replies within one business day, Sunday to Friday. By booking, you agree we may contact you about Kuver Books (privacy notice).