Authentication

API keys, the OTP flow, and how humans and agents authenticate.

Every request to /context and /runtime authenticates with an API key:

bash
curl https://api.superior.trade/context/venues \
  -H "x-api-key: st_live_4f2a9c81d7e3b0…"

Keys are prefixed st_live_. There is no test-key tier — paper mode is how you rehearse without capital.

How you get a key#

Two paths issue keys; both end at the same place.

The OTP flow (built for agents): POST /account/register emails a six-digit code, and POST /account/verify exchanges it for a session token and an api_key, returned once in the response body. The human only ever handles a short-lived code, never the key itself — so an agent can complete onboarding by asking its operator to read six digits aloud.

The dashboard flow (built for humans): sign in at account.superior.trade and mint keys from the Keys page. Same keys, same permissions.

Identity behind both flows is anchored by Privy — that's how account creation works internally. The same account uses the default managed trading wallet today; BYOK credentials are coming soon. API keys authenticate the account, not a specific custody choice.

Key handling rules#

  • The key is shown once. Superior stores only a salted hash and a display prefix (st_live_4f2a9c…).
  • Up to 10 active keys per account; revoke and rotate freely via /account/keys.
  • Send the key only in the x-api-key header — never in a URL, never in strategy code or config (both are stored and log-adjacent).
  • If a key leaks, revoke it immediately: DELETE /account/keys/:id takes effect within seconds.

Scopes#

Keys are full-access to the owning account in the initial release. Scoped keys (read-only context keys, per-deployment keys) are on the roadmap and recorded in the design log; the shape is reserved as a scopes array on the key object so adding them later isn't a breaking change.

Errors#

StatusCodeMeaning
401unauthorizedAPI key or authenticated Privy session is missing, invalid, or not accepted for this route
429rate_limitedSee rate limits; the response carries retry-after