/user WebSocket namespace require a trading API key, secret and passphrase.
Credentials
Configure your bot with:REST HMAC Headers
Every authenticated REST request must include:
The signature message is:
- The four parts are joined with one newline character (
\n, byte0x0A) between each, and no newline followsbody. A request without a body therefore ends with the newline that precedes the empty body. methodis uppercase, such asGET,POSTorDELETE.pathWithQueryincludes/api/v1and the query string exactly as sent, including the?, and excludes the scheme and host. With no query string it is just the path.bodyis the request body exactly as sent, byte for byte. Serialize it once into a variable, then sign and send that same string. Signing a separate re-serialization of your object produces a different signature.- Timestamps must be within 30 seconds of server time.
Legacy Signature Message
The original message is still accepted, with no retirement date set, so existing bots keep working unchanged:path excludes the query string, and body is a re-serialization of the parsed JSON rather than the bytes you sent. Inserting newlines into a legacy message does not produce a valid recommended-form signature.
For a GET request to /api/v1/markets/user-positions?id=abc&id=def with timestamp 1699123456789 and no body, the two forms sign:
Each
\n above is one newline character, not the two characters \ and n.
Where the Legacy Message Is Required
The recommended message is built from the raw request body the server captured. Where there is no raw body to capture, only the legacy message can match. Two cases matter in practice:- File uploads. A
multipart/form-datarequest has no raw body available to the server, so a signature over the bytes you sent cannot match. - The
/userWebSocket handshake. WebSocket authentication runs through a different service that builds only the concatenated message. See WebSocket Auth.
REST Signing Examples
- TypeScript
- Python
- Rust
WebSocket Auth
The/user Socket.IO namespace authenticates after connect with a user-connect message.
The WebSocket signature message is different from REST:
user-authenticated with { "success": true } or { "success": false, "error": "..." }.
Authentication Failures
A REST request whose trading API key fails authentication returns401 with the message Authentication failed. The response does not say which check failed, so work through the causes in order:
- A required header is missing.
- The timestamp is outside the 30 second window, usually because the host clock has drifted.
- The API key is unknown or no longer active.
- The passphrase does not match the key.
- The signature matches neither accepted message.
Invalid signature or Invalid passphrase, stop: those strings are no longer returned.
The one exception is a key that could not be checked, which never gets a 401. A request whose key could not be checked against its current credentials, because the auth service could not be asked about it or did not answer with them or a refusal, returns 503 with error: CREDENTIAL_UNVERIFIABLE and no Retry-After header instead. Your key was not checked, so re-send the request, signed again with a fresh hit-timestamp, and keep the key.
Security Notes
- Keep API secrets out of source control and client-side browser code.
- Use separate keys for separate bots or services.
- Deactivate unused or compromised keys immediately.
- Keep host clocks synchronized; requests outside the timestamp window are rejected.