Agent-readable docs index: /llms.txt. Full docs in one file: /llms-full.txt. Download /docs.zip to grep all markdown files locally.

Open a session

POST /v1/session
Sign message exactly as returned, as a personal message (personal_sign), then:
POST /v1/session
body addressstringrequired
The same address.
body challengestringrequired
The challenge, as returned.
body signaturestringrequired
65 bytes, 0x-prefixed hex.
Response
{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expires": 1793586400 }
A token lasts 24 hours and names one address. Any of the exchange's gateways accepts it.
The message names the site the request came through, so the challenge and the session request must reach the gateway at the same host and scheme. A signature over a message issued for another host is refused with 401.
StatusMeaning
401The challenge expired or was not issued here, or the signer is neither the address nor a key it registered
422A field is missing or malformed

Use it

Send the token as Authorization: Bearer <token>, or as ?token=<token> where you cannot set a header (a browser WebSocket, for one).
import requests from eth_account import Account from eth_account.messages import encode_defunct acct = Account.from_key(PRIVATE_KEY) ch = requests.post(f"{GATEWAY}/v1/session/challenge", json={"address": acct.address}).json() sig = acct.sign_message(encode_defunct(text=ch["message"])).signature tok = requests.post(f"{GATEWAY}/v1/session", json={ "address": acct.address, "challenge": ch["challenge"], "signature": "0x" + sig.hex(), }).json()["token"] me = requests.get(f"{GATEWAY}/v1/account/{acct.address}", headers={"Authorization": f"Bearer {tok}"}).json()