POST /v1/sessionmessage exactly as returned, as a personal message (personal_sign), then:POST /v1/sessionbody addressstringrequiredbody challengestringrequiredbody signaturestringrequired0x-prefixed hex.1{ "token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...", "expires": 1793586400 }
401.| Status | Meaning |
401 | The challenge expired or was not issued here, or the signer is neither the address nor a key it registered |
422 | A field is missing or malformed |
Authorization: Bearer <token>, or as ?token=<token> where
you cannot set a header (a browser WebSocket, for one).12345678910111213import 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()