Skip to content

Signatures

Incognito Payments uses HMAC-SHA256 signatures, keyed with your private key, in two places. Both produce a lowercase hex string. This is the same scheme Tripay uses, so existing Tripay signing code works unchanged.

Sent in the body of Create transaction as the signature field. It proves you hold the private key before we create anything.

signature = HMAC_SHA256( merchant_code + merchant_ref + amount ) keyed with your private key, where amount is the integer rendered as a string.

So for merchant M0001, ref ORDER-1001, amount 150000, the signed string is exactly M0001ORDER-1001150000.

import { createHmac } from "node:crypto";
const signature = createHmac("sha256", privateKey)
.update(`${merchantCode}${merchantRef}${amount}`)
.digest("hex");
// Or, with the SDK:
const sig = payments.signature("ORDER-1001", 150000);

If you use an SDK, you usually never compute this by hand — createTransaction signs the request for you.

Sent by us in the X-Callback-Signature header when we POST a callback to your server. It proves the callback really came from Incognito Payments.

X-Callback-Signature = HMAC_SHA256( raw_request_body ) keyed with your private key.

The signature is computed over the exact bytes of the JSON body we send. Verify it over the raw body you receive — do not re-serialize the parsed JSON first, because key order or whitespace can differ and the signature will not match.

import { createHmac, timingSafeEqual } from "node:crypto";
function verifyCallback(rawBody: string, header: string, privateKey: string) {
const expected = createHmac("sha256", privateKey).update(rawBody).digest("hex");
const a = Buffer.from(expected);
const b = Buffer.from(header);
return a.length === b.length && timingSafeEqual(a, b);
}
// Or, with the SDK:
payments.verifyCallback(rawBody, req.header("X-Callback-Signature") ?? "");

The private key that matches the environment of the transaction is used:

  • A sandbox transaction (created with the DEV- key) is signed with your sandbox private key (devsk-…).
  • A production transaction is signed with your production private key (prodsk-…).

If a callback fails to verify, check that you are using the private key for the right environment.