Authentication
Every request carries three headers. There is no JWT/OAuth — the signature is the authentication.
| Header | Value |
|---|---|
X-Api-Key | Your apiKeyId. |
X-Timestamp | Current Unix time in milliseconds, as a string. Must be within ±5 minutes of our server clock. |
X-Signature | Lowercase hex of HMAC-SHA256(secret, "{X-Timestamp}.{signedBody}"). |
The signed string is the timestamp, a literal dot (.), then the signed
body:
- Award (
POST /v1/ep/webhook):signedBody= the exact raw request body bytes you send. - Status (
GET …/transactions/{orderId}):signedBody= theorderIdpath segment (no body). - History (
GET …/awards):signedBody= thetenantIdquery value (limitandcursorare not signed).
X-Signature = hex( HMAC_SHA256( secret, X-Timestamp + "." + signedBody ) )- The timestamp window (±5 min) plus the per-
orderIdidempotency key together block replay attacks. Keep your server clock synced with NTP. - Signatures are compared in constant time. A wrong/short/non-hex signature is rejected.
- An unknown
apiKeyIdreturns the same401 INVALID_SIGNATUREas a bad signature — we don’t reveal whether a key exists.
Ready-to-run signing code for each endpoint is on Signing & code examples.
Secret rotation
Section titled “Secret rotation”During a rotation you may be issued a secondary secret with an expiry. We accept a signature made with either the primary or the live secondary until the secondary expires. Switch your signing key to the new secret before the window closes; no downtime is required.