Skip to main content
OCX authenticates you with Sign-In With Ethereum (SIWE, EIP-4361). You prove control of your wallet by signing a message; the exchange returns a session that authorizes your trading, wallet, and account requests. For automation, you then mint scoped API keys. All requests go through the API gateway, referred to below as {BASE_URL}.

Authentication tiers

Public

No credentials. All market-data reads and public streams.

Session

A SIWE sign-in yields an httpOnly session cookie (7-day validity). Required for placing orders and viewing your account, wallet, and keys.

API key

An x-api-key header for programmatic access. Scoped read or trade. Accepted on high-throughput trading paths (previews, bulk quotes, cancel-all, algo streams).
API keys are created and revoked only from a signed-in session — a key cannot mint or revoke another key.

Sign in with your wallet

1

Request a nonce

Ask the gateway for a one-time, short-lived nonce to include in your signed message.
POST {BASE_URL}/auth/nonce
{ "walletAddress": "0xYourAddress" }
→ { "nonce": "a1b2c3…" }
The nonce is single-use. Request a fresh one on each sign-in.
2

Build and sign a SIWE message

Construct a standard EIP-4361 message in your wallet. It must include the nonce from step 1, the correct chainId and request uri/domain for OCX, and an expirationTime within the allowed window. Sign it with your wallet (for example personal_sign or wagmi’s signMessage).
A signature minted for another site or chain is rejected — there is no cross-domain replay.
3

Verify and open a session

Submit the exact message string and its signature. On success the response sets the session cookie and returns your identity.
POST {BASE_URL}/auth/siwe
{ "message": "<the exact SIWE message string>", "signature": "0x<signature>" }
→ { "userId": "01H…", "walletAddress": "0xa1b2…c3d4" }
4

Make authenticated requests

In a browser the cookie is sent automatically. Confirm the current session or end it with the session helpers:
GET  {BASE_URL}/auth/me       # → { userId, walletAddress }
POST {BASE_URL}/auth/logout   # revokes the current session everywhere
New accounts may require an invite before trading is enabled. If invite gating is active, redeem a code once while authenticated: POST {BASE_URL}/auth/redeem-invite with { "code": "…" }.

End-to-end example

# 1. request a nonce
NONCE=$(curl -s -X POST {BASE_URL}/auth/nonce \
  -H 'Content-Type: application/json' \
  -d '{"walletAddress":"0xabc..."}' | jq -r .nonce)

# 2. build a SIWE message including $NONCE and sign it in your wallet → $MSG, $SIG

# 3. verify and capture the session cookie
curl -s -c cookies.txt -X POST {BASE_URL}/auth/siwe \
  -H 'Content-Type: application/json' \
  -d "{\"message\":\"$MSG\",\"signature\":\"$SIG\"}"

# 4. authenticated call using the cookie jar
curl -s -b cookies.txt {BASE_URL}/wallet/balance

Provision an API key for automation

For bots, market makers, and agents, sign in once with SIWE, then mint an API key scoped to what the client needs.
1

Create the key

POST {BASE_URL}/perps/me/api-keys
{ "name": "mm-bot-1", "scope": "trade", "allowedIps": ["203.0.113.7"], "expiresInDays": 90 }
→ { "id": "01H…", "name": "mm-bot-1", "scope": "trade", "secret": "ocx_sk_…" }
The secret is shown once only and can never be retrieved again. Copy it immediately into a secret store — never commit it to code or logs.
2

Send it on every request

Attach the secret as a header on subsequent automated calls:
curl -H "x-api-key: ocx_sk_…" {BASE_URL}/perps/orders/preview -d '…'
3

List, rotate, and revoke

GET    {BASE_URL}/perps/me/api-keys        # metadata only; secrets never returned
DELETE {BASE_URL}/perps/me/api-keys/{id}   # revoke
Set expiresInDays for scheduled rotation and pin allowedIps to your egress IPs. Grant least privilege — read for monitoring, trade for execution.

Scopes and access

CapabilityPublicSessionAPI key
Market-data reads and public streams
Order preview, bulk quotes, cancel-all, algo streams✓ (trade)
Place/cancel single orders, view your account & positions
Create / revoke API keys

Rate limits

Requests are rate-limited per client. Authenticated and API-key traffic receives higher limits than anonymous traffic. Every response carries standard X-RateLimit-* headers.
Back off when X-RateLimit-Remaining reaches 0, and handle 429 responses with retry-after logic rather than retrying blindly.