Authentication & agent keys
Public reads need no key. Anything that moves funds requires a scoped agent key whose risk policy is enforced server-side, before any order reaches a venue.
How agent keys work
A human owner authenticates with their multi (Dynamic) session JWT and mints keys for their agents. Each key looks like multi_sk_live_… (or multi_sk_test_…) and carries two things: a set of scopes (what it may do) and a risk policy (how much it may do). A key always trades the owner's own wallet.
- 1Mint a key (owner JWT)mint a key
curl -X POST https://multi-venym-labs.vercel.app/api/agent/keys \ -H "Authorization: Bearer <your-multi-jwt>" \ -H "Content-Type: application/json" \ -d '{ "label": "momentum-bot", "scopes": ["market:read", "account:read", "orders:execute", "pairs:execute"], "policy": { "executionEnabled": true, "maxOrderUsd": 500, "dailyNotionalUsd": 2500, "maxLeverage": 5, "venuesAllow": ["hyperliquid", "lighter"], "marketsAllow": ["BTC", "ETH", "SOL"], "maxSlippageBps": 50 } }' - 2Store the secret once
The raw
multi_sk_…secret is returned once, at mint or rotate — multi stores only a salted hash. Put it in an env var (MULTI_API_KEY); never ship a key in client-side code. - 3Send it on every requesthttp
Authorization: Bearer multi_sk_live_... # or x-multi-key: multi_sk_live_...
POST /api/agent/keys/{id}/rotate — the old secret is revoked and a new one is minted in one call.Scopes
A key carries a set of scopes. Each tool / endpoint declares the scope it needs.
Risk policy
Every key carries a risk policy. Requests that breach it are rejected with a 403 / 429 before reaching a venue. Omitted caps fall back to conservative defaults.
executionEnabledbooleandefault falseMaster switch — fail-closed. No execution of any kind until the owner sets this true.
maxOrderUsdnumberdefault $100Per-order notional ceiling (USD).
dailyNotionalUsdnumberdefault $500Rolling 24h (UTC-day) notional cap across all execution.
maxLeveragenumberdefault 10xMaximum leverage for perp orders.
venuesAllowstring[]Allowlist of venues, e.g. ["hyperliquid","lighter"]. Empty = all venues.
marketsAllow / marketsDenystring[]Symbol allow / deny lists, e.g. ["BTC","ETH"]. Deny wins over allow.
swapChainsAllow(string|number)[]Allowlist of chain IDs for swaps. Empty = all chains.
swapMaxUsdnumberdefault $100Per-swap value ceiling (USD).
maxSlippageBpsnumberdefault 100Hard slippage cap (basis points). Any requested slippage is clamped to this.
ipAllowstring[]Optional IP allowlist for the key.
rateLimits{ read?, execute?, swap? }default 600 / 60 / 30 per minPer-key request limits by class. Defaults: read 600/min, execute 60/min, swap 30/min.
Example
{
"label": "momentum-bot",
"scopes": ["market:read", "account:read", "orders:execute", "pairs:execute"],
"policy": {
"executionEnabled": true,
"maxOrderUsd": 500,
"dailyNotionalUsd": 2500,
"maxLeverage": 5,
"venuesAllow": ["hyperliquid", "lighter"],
"marketsAllow": ["BTC", "ETH", "SOL"],
"maxSlippageBps": 50
}
}Managing keys
Key management is authenticated with your multi (Dynamic) session JWT — a human owner mints keys for their agents. A key always trades the owner's own wallet.
Auth errors
- —
401 UNAUTHORIZED— missing, invalid, or revoked key. - —
403 INSUFFICIENT_SCOPE— the key lacks the required scope. - —
403 EXECUTION_DISABLED—policy.executionEnabledis not true. - —
403 ORDER_TOO_LARGE / LEVERAGE_TOO_HIGH / VENUE_NOT_ALLOWED— a policy cap was breached. - —
429 RATE_LIMITED / DAILY_CAP— per-key rate limit or daily notional cap hit.
See the safety model for the full error catalog.