TokenPay DevelopersMerchant Dashboard

Authentication

TokenPay uses API keys for identification and HMAC-SHA256 signatures for request integrity. Both are required on every live-mode request.

API keys

Every request must carry a bearer token in the Authorization header:

Authorization: Bearer tp_live_abc123...

Two key scopes exist:

  • tp_test_* — test mode. No funds move. No signature required. Great for local development.
  • tp_live_* — production. Real money. HMAC signature required on all POST / PUT / DELETE requests.

HMAC request signing

Live-mode requests that mutate state must include an X-TokenPay-Signature header. The signature is a hex-encoded HMAC-SHA256 of the canonical request string using your API key's secret as the HMAC key.

Canonical string

Assemble the canonical string as:

<METHOD>\n<PATH>\n<TIMESTAMP>\n<BODY_SHA256_HEX>
  • METHOD — uppercase HTTP verb, e.g. POST.
  • PATH — full request path including query string, e.g. /v1/payments.
  • TIMESTAMP — Unix epoch seconds. Send the same value in X-TokenPay-Timestamp. Requests more than 5 minutes skew are rejected.
  • BODY_SHA256_HEX — lowercase hex SHA-256 of the raw request body. Use the empty-string SHA-256 for GETs.

Example — Node.js

import crypto from 'node:crypto';

const secret = process.env.TOKENPAY_SECRET!;
const body = JSON.stringify({ amount: '10.00', currency: 'AUD' });
const timestamp = Math.floor(Date.now() / 1000).toString();
const bodyHash = crypto.createHash('sha256').update(body).digest('hex');

const canonical = ['POST', '/v1/payments', timestamp, bodyHash].join('\n');
const signature = crypto
  .createHmac('sha256', secret)
  .update(canonical)
  .digest('hex');

await fetch('https://api.tokenpayment.io/v1/payments', {
  method: 'POST',
  headers: {
    'Authorization': `Bearer ${process.env.TOKENPAY_API_KEY}`,
    'Content-Type': 'application/json',
    'X-TokenPay-Timestamp': timestamp,
    'X-TokenPay-Signature': signature,
  },
  body,
});

Example — Go

import (
    "crypto/hmac"
    "crypto/sha256"
    "encoding/hex"
    "fmt"
    "strconv"
    "time"
)

body := []byte(`{"amount":"10.00","currency":"AUD"}`)
ts := strconv.FormatInt(time.Now().Unix(), 10)
sum := sha256.Sum256(body)
bodyHash := hex.EncodeToString(sum[:])

canonical := fmt.Sprintf("POST\n/v1/payments\n%s\n%s", ts, bodyHash)
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(canonical))
signature := hex.EncodeToString(mac.Sum(nil))

Key rotation

Rotate keys from the dashboard at Settings → API Keys → Rotate. Rotation issues a new secret immediately; the old secret remains valid for 24 hours to let you roll deployments without downtime.

IP allowlisting (optional)

Live keys can be pinned to a list of source IP addresses. Requests from other addresses are rejected with HTTP 403 and error code ip_not_allowed. Configure allowlists from the key detail screen.