Three ways in: none, a key, or a session
Market data needs no credentials. Agent actions need an API key. Managing keys themselves needs a logged-in session.
Updated
The three models
| Model | Credential | What it unlocks |
|---|---|---|
| Public | — | Tokens, quotes, trades, candles, stats, SSE streams, config |
| API key | X-API-Key: vectr_… | Agent jobs (which can create orders with a read-write key) and wallet actions, scoped to the account's wallet. The /orders endpoints themselves take a session |
| Session | vectr_session cookie (X sign-in) | Creating and managing API keys, agent profiles, account settings |
- Public
- Credential
- —
- What it unlocks
- Tokens, quotes, trades, candles, stats, SSE streams, config
- API key
- Credential
- X-API-Key: vectr_…
- What it unlocks
- Agent jobs (which can create orders with a read-write key) and wallet actions, scoped to the account's wallet. The /orders endpoints themselves take a session
- Session
- Credential
- vectr_session cookie (X sign-in)
- What it unlocks
- Creating and managing API keys, agent profiles, account settings
An API key is never a grant beyond its wallet — every option on a key is a restriction, and a read-only key cannot reach the signing path at all.
Sessions
A session is created by signing in with X. GET /auth/login redirects to X OAuth; the callback sets a 7-day HttpOnly cookie named vectr_session. Session endpoints:
- GET /auth/login
- Start the X OAuth flow (?returnTo)
- GET /auth/me
- Current user: wallet, handle, pfp — 401 when logged out
- GET /auth/session
- Same payload but user:null with a 200 for visitors
- GET /auth/logout
- Clear the session cookie
- GET /auth/user/:wallet
- Public profile lookup by wallet
Creating a key
The UI path: sign in on vectr.bot, open your profile, and create a key under API keys. The same operation exists over the session-authenticated API:
- POST /api-keys
- Create a key. Body: name?, readOnly?, allowedIps?, allowedRecipients?
- GET /api-keys
- List this account's keys
- DELETE /api-keys/:id
- Revoke a key immediately
curl -X POST https://api.vectr.bot/api-keys \
-H "Cookie: vectr_session=…" -H "Content-Type: application/json" \
-d '{"name":"research-bot","readOnly":true}'The raw key is returned once, at creation — store it then. Keys are vectr_ plus 24 random bytes, hex.
Scoping a key down
| Field | Type | Effect |
|---|---|---|
| readOnly | boolean | Blocks the signing path entirely — reads and agent planning still work |
| allowedIps | string[] (max 50) | IPv4 addresses or CIDR ranges the key may be used from |
| allowedRecipients | address[] (max 50) | Contract addresses a read-write key may send transactions to — for a bot, pin it to its own curve |
- readOnly
- Type
- boolean
- Effect
- Blocks the signing path entirely — reads and agent planning still work
- allowedIps
- Type
- string[] (max 50)
- Effect
- IPv4 addresses or CIDR ranges the key may be used from
- allowedRecipients
- Type
- address[] (max 50)
- Effect
- Contract addresses a read-write key may send transactions to — for a bot, pin it to its own curve
A default read-write key can ask the backend to sign and broadcast through the wallet it belongs to. If a script only needs to research, create it read-only — there is no reason to carry the wider permission.
Using the key
curl -X POST https://api.vectr.bot/agent/job \
-H "X-API-Key: vectr_…" -H "Content-Type: application/json" \
-d '{"prompt":"buy 0.01 ETH of 0x… when it dips below the current price"}'Keys are checked on every request. Revoking takes effect immediately — a leaked key stops working the moment you delete it from your profile.
Signing
POST /wallet/sign-and-submit accepts a session or an API key and broadcasts through the account's custodial wallet (30 requests/minute, stricter than the global limit). This is the intended automation path — a read-write key can sign without a person in the loop, which is exactly why the restrictions exist:
- readOnly keys are rejected outright — 403, before the request reaches the signer.
- allowedRecipients pins which contracts a key may send to — the signer re-checks
tobefore it touches the wallet key. - allowedIps is evaluated per request, so a leaked key from a foreign host is dead on arrival.
The body is a built transaction (to, data, value?, approvalStep?) plus a required txType. The signer checks the calldata's function and target against it; a missing or mismatched type is a 403.
| txType | Signs |
|---|---|
| buy, sell | A build-tx result: the curve, or the Uniswap router after graduation |
| launch | launchToken or launchTokenAndBuy on the factory |
| claim | claimCreatorFees or claimCreatorFeesToken on the FeeCollector. An agent's richData calls this claim_fees; send claim |
| transfer | An ERC-20 transfer |
| buy_credits | depositPlatformFee on the FeeCollector |
| subscribe | A plain value transfer, no calldata |
- buy, sell
- Signs
- A build-tx result: the curve, or the Uniswap router after graduation
- launch
- Signs
- launchToken or launchTokenAndBuy on the factory
- claim
- Signs
- claimCreatorFees or claimCreatorFeesToken on the FeeCollector. An agent's richData calls this claim_fees; send claim
- transfer
- Signs
- An ERC-20 transfer
- buy_credits
- Signs
- depositPlatformFee on the FeeCollector
- subscribe
- Signs
- A plain value transfer, no calldata
Where the human confirmation lives
The agent surfaces — CLI, MCP, the terminal — always return the transaction for a person to confirm; they never call the signer themselves. Direct sign-and-submit access is for bots you deliberately arm. Default to read-only and add permissions only as needed.