Three schemes. Pick by use case. Sandbox and production use the same schemes but different key prefixes.
| Scheme | Use case | Header(s) | Prefix |
|---|---|---|---|
| API Key | Machine-to-machine, creator profiles, aggregators | X-Api-Key |
sk_live_* / sk_test_* |
| HMAC (Polymarket-compatible) | High-security trading bots, request-signing partners | 5 × POLY_* |
Same as API Key |
| Session Bearer | Browser / mobile client flows | Authorization: Bearer <token> |
Session-scoped |
Send the key in the X-Api-Key header. No signing. Rate-limited per key.
curl https://predictasiax.com/api/v1/account \
-H "X-Api-Key: sk_live_YOUR_KEY_HERE"
Via the dashboard (Settings → API Keys → Mint new key) or via REST:
curl -X POST https://predictasiax.com/api/v1/keys \
-H "Authorization: Bearer <session_token>" \
-H "Content-Type: application/json" \
-d '{
"label": "my-arb-bot",
"permissions": ["read", "trade"]
}'
Response (shown once — cannot be retrieved again):
{
"ok": true,
"data": {
"key_id": "sk_live_ABC123",
"secret": "<32-bytes-hex>",
"passphrase": "<human-readable>",
"permissions": ["read", "trade"],
"created_at_ms": 1786190400000
}
}
| Key prefix | Environment | Wrong-env behavior |
|---|---|---|
sk_live_* LIVE |
Production only (predictasiax.com) |
401 WRONG_ENV_KEY if used on sandbox |
sk_test_* TEST |
Sandbox only (sandbox.predictasiax.com) |
401 WRONG_ENV_KEY if used on production |
For higher-security trading bots. Every request is signed with your secret. Server verifies signature + timestamp within 30-second skew window.
| Header | Value |
|---|---|
POLY_ACCESS_KEY | Your key_id (e.g., sk_live_ABC123) |
POLY_TIMESTAMP | UNIX ms epoch, must be within 30s of server time |
POLY_PASSPHRASE | Your passphrase from key mint |
POLY_SIGNATURE | base64(HMAC-SHA256(secret, message)) |
Content-Type | application/json for POST/PUT/PATCH |
message = timestamp + method + path + body
# Examples:
# GET /v1/markets?category=crypto (no body) → "1786190400000GET/v1/markets?category=crypto"
# POST /v1/orders {"market_id":"m_abc"} → "1786190400000POST/v1/orders{\"market_id\":\"m_abc\"}"
import hmac, hashlib, base64, time, json, requests
KEY_ID = "sk_live_ABC123"
SECRET = "<32-bytes-hex>"
PASSPHRASE = "correct-horse-battery-staple"
BASE = "https://predictasiax.com/api"
def sign(method, path, body=""):
ts = str(int(time.time() * 1000))
message = ts + method + path + body
sig = base64.b64encode(
hmac.new(SECRET.encode(), message.encode(), hashlib.sha256).digest()
).decode()
return {
"POLY_ACCESS_KEY": KEY_ID,
"POLY_TIMESTAMP": ts,
"POLY_PASSPHRASE": PASSPHRASE,
"POLY_SIGNATURE": sig,
"Content-Type": "application/json",
}
# GET
r = requests.get(BASE + "/v1/account", headers=sign("GET", "/v1/account"))
# POST
body = json.dumps({"market_id": "m_abc", "outcome_id": "yes",
"side": "buy", "order_type": "market", "size": "100"})
r = requests.post(BASE + "/v1/orders", headers=sign("POST", "/v1/orders", body), data=body)
print(r.json())
import crypto from "node:crypto";
const KEY_ID = "sk_live_ABC123";
const SECRET = "<32-bytes-hex>";
const PASSPHRASE = "correct-horse-battery-staple";
const BASE = "https://predictasiax.com/api";
function sign(method, path, body = "") {
const ts = Date.now().toString();
const message = ts + method + path + body;
const sig = crypto.createHmac("sha256", SECRET).update(message).digest("base64");
return {
"POLY_ACCESS_KEY": KEY_ID,
"POLY_TIMESTAMP": ts,
"POLY_PASSPHRASE": PASSPHRASE,
"POLY_SIGNATURE": sig,
"Content-Type": "application/json",
};
}
// GET
const r1 = await fetch(BASE + "/v1/account", { headers: sign("GET", "/v1/account") });
// POST
const body = JSON.stringify({ market_id: "m_abc", outcome_id: "yes",
side: "buy", order_type: "market", size: "100" });
const r2 = await fetch(BASE + "/v1/orders", {
method: "POST", body, headers: sign("POST", "/v1/orders", body),
});
console.log(await r2.json());
#!/bin/bash
KEY_ID="sk_live_ABC123"
SECRET="<32-bytes-hex>"
PASSPHRASE="correct-horse-battery-staple"
BASE="https://predictasiax.com/api"
sign() {
local method="$1" path="$2" body="$3"
local ts=$(date +%s%3N)
local message="${ts}${method}${path}${body}"
local sig=$(printf '%s' "$message" | openssl dgst -sha256 -hmac "$SECRET" -binary | base64)
echo "-H POLY_ACCESS_KEY:${KEY_ID} -H POLY_TIMESTAMP:${ts} -H POLY_PASSPHRASE:${PASSPHRASE} -H POLY_SIGNATURE:${sig}"
}
# GET
curl "${BASE}/v1/account" $(sign GET /v1/account)
# POST
body='{"market_id":"m_abc","outcome_id":"yes","side":"buy","order_type":"market","size":"100"}'
curl -X POST "${BASE}/v1/orders" -H "Content-Type:application/json" $(sign POST /v1/orders "$body") -d "$body"
Server rejects with 401 INVALID_SIGNATURE if any of:
POLY_SIGNATUREDELETE /v1/keys/{id} called earlier)Not intended for machine partners. Browser client obtains a bearer token from POST /api/auth/login, sends on every request:
curl https://predictasiax.com/api/v1/account \
-H "Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9..."
Session tokens expire after 7 days idle (24h if refresh not performed). Machine partners should always prefer API Key + HMAC.
The WS connection accepts anonymous connections for public channels (fast_tick, ticker, orderbook, markets_snapshot). To subscribe to private channels (account, deposit, etc.), send an AUTH message after connect:
wscat -c wss://predictasiax.com/ws
> {"method":"AUTH","token":"sk_live_ABC123"}
< {"type":"authenticated","email":"partner@example.com"}
> {"method":"SUBSCRIBE","params":["account","fast_round_settled"]}
You can pass either the API key or a session bearer as token — server handles both.
curl -X DELETE https://predictasiax.com/api/v1/keys/sk_live_ABC123 \
-H "Authorization: Bearer <session_token>"
Effective within 5 seconds across our backend fleet. All subsequent requests using the revoked key return 401 KEY_REVOKED.
SECRET and PASSPHRASE in a secret manager (AWS Secrets Manager, GCP Secret Manager, HashiCorp Vault). Rotate on any suspicion of leak — old key can be revoked via DELETE /v1/keys/{id}.