API Key & HMAC signing¶
Evidence: ptrader-api-gateway/docs/API-Authentication-Mechanism.en.md, filter/AuthFilter.java, Postman collection pre-request script.
Headers¶
| Header | Required | Description |
|---|---|---|
x-ptrader-apikey |
Yes (signed & key-only) | API key |
true-client-ip / x-real-ip |
Often required via ingress | Client IP; Postman sets true-client-ip |
Signed requests¶
Required for endpoints annotated @SignAuth without validKeyOnly (orders, account, wallet, etc.).
Parameters¶
| Parameter | Required | Description |
|---|---|---|
timestamp |
Yes when checkRecvWindow=true |
Unix ms |
recvWindow |
No | Default 5000 ms, max 60000 ms |
signature |
Yes | HMAC-SHA256 hex (query or header) |
Recv window rule¶
Valid when:
timestamp ≤ serverTime + 1000 and serverTime - timestamp ≤ recvWindow
Signature string (originStr)¶
Rules:
- Query: all parameters except
signature, in the order sent, joined with&askey=value. - Body:
application/json→ compact JSON string (gateway parses then re-serializes via JacksonJsonNode.toString()).application/x-www-form-urlencoded→ form fields not already in query (excludesignature).- Concatenate query and body with no extra separator.
Worked example (LIMIT order, query-only body empty)¶
Illustrative credentials (from api-gateway auth doc — not production keys):
- API Key:
vmPUZE6mv9SD5VNHk4HlWFsOr6aKE2zvsw0MuIgwCIPy6utIco14y7Ju91duEh8A - API Secret:
NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j
API_KEY="vmPUZE6mv9SD5VNHk4HlWFsOr6aKE2zvsw0MuIgwCIPy6utIco14y7Ju91duEh8A"
API_SECRET="NhqPtmdSJYdKjVHjA7PZj4Mge3R5YNiP1e3UZjInClVN65XAbvqqM6A7H5fATj0j"
BASE_URL="https://api-gateway-scb.dev.pcrypto.com"
TIMESTAMP=$(python3 -c 'import time; print(int(time.time()*1000))')
QUERY="symbol=BTCUSDT&side=BUY&type=LIMIT&timeInForce=GTC&quantity=0.001&price=50000×tamp=${TIMESTAMP}&recvWindow=5000"
SIGNATURE=$(printf '%s' "${QUERY}" | openssl dgst -sha256 -hmac "${API_SECRET}" | awk '{print $2}')
curl -sS -X POST "${BASE_URL}/openapi/v1/order?${QUERY}&signature=${SIGNATURE}" \
-H "x-ptrader-apikey: ${API_KEY}" \
-H "true-client-ip: 1.2.3.4" \
-H "Content-Type: application/x-www-form-urlencoded"
For JSON bodies, append the compact JSON string to originStr after the query string (Postman script: JSON.stringify(JSON.parse(raw))).
Key-only endpoints (listenKey)¶
POST|PUT|DELETE /openapi/v1/userDataStream use @SignAuth(validKeyOnly = true, accountOnly = true).
Evidence: UserDataApiController; AuthFilter branch signAuth.validKeyOnly() validates the key via broker-security without building/checking a signature.
Send x-ptrader-apikey only (Postman X-Skip-Sign is a client-side hint and is not interpreted by the gateway).
Org resolution¶
BrokerInterceptor resolves x-org-id from Host → broker apiDomain. Failure → INVALID_PARAMETER (host).