Authentication
Create CLOB credentials and sign private requests
The CLOB API uses two authentication levels. L1 proves control of a wallet; L2 signs trading and account requests with credentials derived from that wallet.
Choose the required level
| Level | Method | Use it for |
|---|---|---|
| Public | No credentials | Markets, books, prices, spreads, and public analytics |
| L1 | EIP-712 wallet signature | Create or derive API credentials |
| L2 | HMAC-SHA256 with API credentials | Private order, cancellation, trade, and account routes |
L2 authenticates the request. A new order still contains an order payload signed by the trader before submission.
Recommended: use an SDK
The TypeScript, Python, and Rust clients create or derive L2 credentials and attach the required headers. See Clients & SDKs.
When implementing authentication directly, synchronize your clock with Get Server Time first.
Create or derive credentials
Use one of the L1 routes:
POST {CLOB_URL}/auth/api-key
GET {CLOB_URL}/auth/derive-api-keySend these headers:
| Header | Required | Description |
|---|---|---|
KUEST_ADDRESS | Yes | Polygon signer address |
KUEST_SIGNATURE | Yes | EIP-712 signature for the auth payload |
KUEST_TIMESTAMP | Yes | Current Unix timestamp in seconds |
KUEST_NONCE | Yes | Auth nonce, commonly 0 |
KUEST_REFERRAL | No | Referral identifier used for attribution |
Sign this EIP-712 shape with the same address sent in KUEST_ADDRESS:
{
"domain": {
"name": "ClobAuthDomain",
"version": "1",
"chainId": 137
},
"types": {
"ClobAuth": [
{ "name": "address", "type": "address" },
{ "name": "timestamp", "type": "string" },
{ "name": "nonce", "type": "uint256" },
{ "name": "message", "type": "string" }
]
},
"message": {
"address": "<signing_address>",
"timestamp": "<unix_timestamp>",
"nonce": "<nonce>",
"message": "This message attests that I control the given wallet"
}
}The response contains:
{
"apiKey": "550e8400-e29b-41d4-a716-446655440000",
"secret": "<generated_secret>",
"passphrase": "<generated_passphrase>"
}Sign an L2 request
Private CLOB routes require all five headers:
| Header | Value |
|---|---|
KUEST_ADDRESS | Polygon signer address |
KUEST_SIGNATURE | HMAC signature for the request |
KUEST_TIMESTAMP | Current Unix timestamp in seconds |
KUEST_API_KEY | API key UUID |
KUEST_PASSPHRASE | Passphrase paired with the API key |
The HMAC input must match the exact timestamp, method, path, and body sent over the wire. Do not serialize the body again after calculating the signature.
Store credentials as secrets
Keep the private key, API secret, and passphrase in a server-side secret store. Do not place them in frontend bundles, logs, analytics, URLs, or support messages.
Troubleshooting
| Symptom | Check |
|---|---|
| Timestamp or expired-signature error | Synchronize with server time and retry |
| Invalid L1 signature | Confirm chain ID, signer address, nonce, and exact message |
| Invalid L2 signature | Confirm method, path, raw body, timestamp, and base64 secret |
| Auth works but order fails | Validate the order signature, funder, balance, and approvals |