Theme switcher

Important Note

⚠️ Important: All Requests Must Be Signed

To ensure request authenticity and integrity, all requests sent from your backend to COUNT's API must be signed using your client secret. This signature helps prevent tampering, replay attacks, and unauthorized access.

We strongly recommend using a reusable Axios instance with request signing built in, as shown below.

🔐 Signature Requirements

Each request must include three critical headers:

  • x-client-id should contain your unique client identifier, which you’ll find in your COUNT dashboard.
  • x-timestamp must be the current UNIX timestamp in seconds when the request is made.
  • x-signature is the computed HMAC SHA-256 signature based on the request details and your client secret.

The signature is generated using a combination of the HTTP method, the request path (excluding domain), the timestamp, and the hashed request body (for POST, PUT, or PATCH methods). These are combined into a single string, hashed using your client secret, and attached to the request.

Below is the recommended setup using a reusable Axios client to handle signing automatically.

JavaScript
const axios = require("axios"); const crypto = require("crypto");
// Create an Axios instance with base URL and static x-client-id header const countClient = axios.create({ baseURL: process.env.COUNT_PARTNER_API_ENDPOINT, headers: { "x-client-id": process.env.COUNT_CLIENT_ID, }, });
// Attach the interceptor with a reusable signing function countClient.interceptors.request.use(signRequest, (error) => Promise.reject(error));
// Function that handles signing the request function signRequest(config) { const method = (config.method || "GET").toUpperCase(); const url = config.url || "/"; const urlPath = new URL(url, config.baseURL).pathname; const timestamp = Math.floor(Date.now() / 1000).toString(); const clientSecret = process.env.COUNT_CLIENT_SECRET; const body = config.data || {};
const signature = generateSignature({ method, path: urlPath, timestamp, body, clientSecret, });
config.headers["x-timestamp"] = timestamp; config.headers["x-signature"] = signature;
return config; }
// Hash the request body using SHA-256 function hashBody(body) { return body && Object.keys(body).length > 0 ? crypto.createHash("sha256").update(JSON.stringify(body)).digest("hex") : ""; }
// Build the HMAC base string in the format: METHOD:/path:timestamp:bodyHash function buildHmacBaseString(method, path, timestamp, bodyHash = "") { return ${method}:${path}:${timestamp}:${bodyHash}; }
// Generate the HMAC-SHA256 signature function generateSignature({ method, path, timestamp, body, clientSecret }) { const bodyHash = ["POST", "PUT", "PATCH"].includes(method) ? hashBody(body) : "";
const baseString = buildHmacBaseString(method, path, timestamp, bodyHash);
return crypto .createHmac("sha256", clientSecret) .update(baseString) .digest("hex"); }

Ensure your server time is accurate and your clientSecret is never exposed on the client side. Requests with invalid or expired signatures will be rejected by COUNT’s API.

Was this section helpful?

What made this section unhelpful for you?

On this page
  • Important Note