Authentication

HMAC-SHA256 signing rules, nonce-based replay protection, and the three credentials you receive at onboarding.

Every authenticated request carries three headers: X-API-KEY, X-API-SIGN, X-API-NONCE. Sign the exact bytes you send — that’s the whole rule. Same in bash, Python, Node; see the worked example below, or jump to the signing template.

Required headers

HeaderRequiredDescription
X-API-KEYYesPublic partner key. May carry an optional code segment: apiKey.codeName— see /v1/codes.
X-API-SIGNYesHex signature of the raw request body, keyed by your apiSecret. The recipe is in the worked example below.
X-API-NONCEYesUnique per request (UUID or 16-byte hex). Reusing a nonce returns code 3 AUTH_INVALID.

Signing rules

  • Sign the exact bytes you put on the wire.
  • For GET /v1/codes the request has no body. Sign the empty string "": same HMAC primitive, zero input bytes. DELETE /v1/codes carries a JSON body {"code":"<code>"}. Sign that exact body, not the empty string.
  • Bad signature, unknown key, replayed nonce, and malformed envelope all collapse to the same response: { code: 3, msg: "AUTH_INVALID" }. You learn whether you got in, never which check failed.

Replay protection

Nonces are tracked server-side. Use a fresh random value per request, 16 to 64 characters. A UUID without hyphens is 32; with hyphens, 36; 64-char hex is also valid. Reuse, under-16, or over-64 all return { code: 3, msg: "AUTH_INVALID" }. There is no timestamp header; caller and server clocks are never compared.

Unauthenticated endpoints

/v1/currencies, /v1/pairs, and /v1/price accept unsigned requests for catalog and un-attributed quoting. Unsigned traffic runs on a separate public bucket and never charges a partner budget. Signed /v1/price calls receive partner-specific markup. Public limits are on the Rate limits page.

End-to-end example

POST /api/v1/price in three languages. The signature is computed over the exact JSON body bytes you send.

# Request a quote for 0.01 BTC -> USDT (Tron) with a 0.5% partner markup.
APIKEY="rWqZ...your-api-key...Rg"
APISECRET="G1JV...your-api-secret...n4"
NONCE=$(openssl rand -hex 16)
BODY='{"type":"float","fromCcy":"btc","toCcy":"usdt_trc20","direction":"from","amount":"0.01","afftax":50}'
SIGN=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "$APISECRET" | sed 's/^.* //')

curl -sS -X POST "https://0trace.io/api/v1/price" \
  -H "Content-Type: application/json" \
  -H "X-API-KEY: $APIKEY" \
  -H "X-API-SIGN: $SIGN" \
  -H "X-API-NONCE: $NONCE" \
  --data "$BODY"

Common mistakes

  • Re-serialising the body before sending. If your HTTP client pretty-prints or sorts keys before transmission, the body on the wire differs from the bytes you signed. Always sign the exact bytes you POST.
  • Mixing keys across requests. The X-API-KEY header and the secret you HMAC with are a pair, issued together at onboarding. The header itself is not part of the HMAC input; only the raw request body is. Use the apiSecret that was provisioned alongside the apiKey you send.
  • Stale, short, or oversized nonces. Generate a fresh random nonce per request, 16–64 characters inclusive. Reusing a value, sending an empty or under-16-character nonce, or sending an over-64-character nonce all return the same X-API-NONCE AUTH_INVALID envelope.

Credential provisioning

Onboarding gives you three secrets through a secure channel:

One-time provisioning bundle
{
  "apiKey": "rWqZ...your-public-key...Rg",
  "apiSecret": "G1JV...your-signing-secret...n4",
  "webhookSecret": "Lh2P...your-webhook-secret...8K"
}

Rotate both at any time through /v1/keys/rotate. The previous value is invalidated immediately.

Partner API.
Same engine as 0trace.

A private partner integration surface. Signed quotes, server-side pricing, webhook delivery, multiple reference codes, and a self-serve cabinet — all backed by the production exchange engine.

Support

Questions? Answers.

Get the latest updates

Follow us on X

The 0trace team will never ask for KYC or AML. We retain no logs, metadata, or tracking cookies.

Learn more