Testnet
Connect to API
Authenticate an owner account with an authorized signer and obtain JWT credentials for REST and WebSocket
Connect to API
Use this guide to authenticate with Cascade and get a JWT bearer token for REST and WebSocket access.
Requirements
Before continuing, complete:
Authenticate with the server
Use the widget below to quickly get an API key for your owner account. The signer can be the owner wallet or a delegate that has already been authorized for that owner account. Once authenticated, you can test the API here.
No API key
Identity mapping
Use these terms consistently across REST and WebSocket calls:
| Role | Example | Where it belongs |
|---|---|---|
| Owner account | 0xAa...01 | The stable trading account identity. Pass this to GET /auth?account=..., REST /account/* routes, and the intended private WS account field. |
| Delegate signer | 0xBb...02 | The wallet that signs the auth challenge or EIP-712 payloads when delegation has been granted for the owner account + subaccount. |
| Subaccount index | 0 | The risk sleeve inside the owner account. Pass this anywhere a private route or channel asks for subaccountIndex. |
Manual authentication steps
1. Request a challenge
curl "https://engine.cascade.cooking/auth?account=<OWNER_ACCOUNT>"2. Sign and POST proof
- Sign
signing_payloadusing EIP-191 (eth_sign/ personal sign) - The signer can be the owner wallet or a delegate wallet that has already been authorized for the target owner account
- POST
{ message, signature, server_signature }back to/auth - Store returned
{ token, claims }
3. Use JWT for REST
Authorization: Bearer <token>4. Authenticate WebSocket
{
"jsonrpc": "2.0",
"id": 1,
"method": "auth",
"params": { "bearer": "<token>" }
}JavaScript example (viem)
import { createWalletClient, custom } from "viem";
const ethereumProvider = /* browser wallet, WalletConnect, embedded signer, etc. */;
const wallet = createWalletClient({ transport: custom(ethereumProvider) });
const ownerAccount = "0x..."; // Cascade owner account
const [delegateAddress] = await wallet.getAddresses();
const challenge = await fetch(
`https://engine.cascade.cooking/auth?account=${ownerAccount}`,
).then((res) => res.json());
const signature = await wallet.signMessage({
account: delegateAddress,
message: challenge.signing_payload,
});
const session = await fetch("https://engine.cascade.cooking/auth", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
message: challenge.message,
signature,
server_signature: challenge.server_signature,
}),
}).then((res) => res.json());
const token = session.token;
await fetch("https://engine.cascade.cooking/account/orders", {
headers: { Authorization: `Bearer ${token}` },
});Python example (web3.py)
import os
import requests
from eth_account import Account
from eth_account.messages import encode_defunct
BASE_URL = "https://engine.cascade.cooking"
OWNER_ACCOUNT = os.environ["OWNER_ACCOUNT"]
delegate = Account.from_key(os.environ["DELEGATE_PRIVATE_KEY"])
challenge = requests.get(
f"{BASE_URL}/auth",
params={"account": OWNER_ACCOUNT},
timeout=10,
).json()
message = encode_defunct(text=challenge["signing_payload"])
signature = Account.sign_message(message, private_key=delegate.key).signature.hex()
session = requests.post(
f"{BASE_URL}/auth",
json={
"message": challenge["message"],
"signature": signature,
"server_signature": challenge["server_signature"],
},
timeout=10,
).json()
token = session["token"]
requests.get(
f"{BASE_URL}/account/orders",
headers={"Authorization": f"Bearer {token}"},
timeout=10,
)