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 inX-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.