Authentication
HTTP Basic for every merchant call. HMAC-SHA512 on detokenize and other signed vault writes.
Basic auth
All /api/v1/* merchant routes use HTTP Basic:
Authorization: Basic base64(apiKey:apiSecret)Keys are created in the dashboard. Each key can have an IP allowlist. Requests from other IPs return IP_NOT_WHITELISTED.
HMAC-SHA512
Detokenize and some vault operations also require X-Signature. Algorithm is HMAC-SHA512. Shared secret is at least 256 bits, issued with the key.
Message (five lines, \n separated):
METHOD
hex(SHA-512(body))
content_type
date
request_uriMETHODis uppercase (POST)bodyis the raw JSON bytes. Empty body hashes the empty string.content_typeis theContent-Typeheader value, or empty when there is no bodydateis theDateheader (RFC 7231, same value you send)request_uriis the path, including query string if you sent one (/api/v1/detokenize)
The header value is Base64 of the HMAC output.
import crypto from 'node:crypto';
export function tokeniSignature({ method, body, contentType, date, path, secret }) {
const bodyHash = crypto.createHash('sha512').update(body ?? '').digest('hex');
const message = [method, bodyHash, contentType ?? '', date, path].join('\n');
return crypto.createHmac('sha512', secret).update(message).digest('base64');
}Verify on your side with crypto.timingSafeEqual. Tokeni does the same.
Idempotency
Send X-Idempotency-Key (UUID) on charges and other writes you might retry. A duplicate key returns DUPLICATE_REQUEST or the original result, depending on the route.
TokenEx headers
/v2/Pci/* uses tx-tokenex-id and tx-apikey instead of Basic. See TokenEx /v2/Pci.
What not to send
Do not put PANs, CVVs, or shared secrets in query strings, logs, or correlationId. Auth failures return opaque codes, not a dump of what we hashed.