symbol decides the market (AAPL, BTC/USD, AAPL241213C00250000).
Naive is not the broker, a broker-dealer, or an investment adviser, and does
not exercise trading discretion — the connected brokerage is the broker. Naive is
a governed gateway in front of your users’ own brokerage accounts: the user
directs and approves the trades. Money-moving actions (place/cancel order, close
position) are approval-gated by default — see Approvals.
CLI First
How the OAuth connection works
Naive owns a single platform OAuth app registered with the brokerage.connect
returns an authorize_url; the user opens it, approves access, and the brokerage
redirects back to Naive’s callback, which exchanges the code for a bearer token
and stores it encrypted. The token is then used to call the brokerage’s trading
API for that user.
Start the flow
{ "authorize_url": "https://<brokerage-oauth>/authorize?...", "env": "paper" }.User authorizes
Open the
authorize_url and approve access. The brokerage redirects to
Naive’s callback (/v1/trading/oauth/callback), which stores the token.Use
--env paper for paper trading and --env live for a funded account. A
user can connect both; when both are connected, pass --env (or env) on each
call. OAuth access tokens are long-lived (there is no refresh token); if access
is ever revoked, calls return unauthorized and you simply reconnect.Disclosure. A disclosure must be shown to the user at connection time.
POST /v1/trading/connect returns it as a disclosure field (and the dashboard
renders it as an “Authorize naive” consent step before redirecting). Display it
before sending the user to the authorize URL.Tools
| Tool | Type | Description |
|---|---|---|
trading_connect | Setup | Start the brokerage OAuth flow (returns an authorize URL) |
trading_connections | Setup | List linked environments (paper/live) and status |
trading_disconnect | Setup | Forget a stored connection |
trading_account | Read | Get the connected brokerage account |
trading_assets | Read | List tradable assets (filter by asset class) |
trading_positions | Read | List open positions |
trading_position | Read | Get one open position |
trading_orders | Read | List orders |
trading_get_order | Read | Get one order |
trading_quote | Read | Latest quote(s) for symbols |
trading_create_order | Core (sensitive) | Place an order |
trading_cancel_order | Core (sensitive) | Cancel an open order |
trading_close_position | Core (sensitive) | Close (liquidate) a position |
Placing orders
The same endpoint trades every asset class — thesymbol selects the market.
Provide either qty (shares/coins) or notional (dollar amount).
Order parameters
| Parameter | Type | Description |
|---|---|---|
symbol | string | Asset symbol — AAPL, BTC/USD, or an OCC option symbol |
side | string | buy or sell |
qty | string | Quantity (shares/coins). Use qty or notional |
notional | string | Dollar amount (fractional). Use notional or qty |
type | string | market (default), limit, stop, stop_limit, trailing_stop |
time_in_force | string | day, gtc, opg, cls, ioc, fok. Crypto supports gtc/ioc |
limit_price | string | Required for limit / stop_limit |
stop_price | string | Required for stop / stop_limit |
order_class | string | simple, bracket, oco, oto (equities) |
extended_hours | boolean | Allow execution during extended hours (equities) |
env | string | paper or live (required if both are connected) |
Naive sends the request’s
Idempotency-Key as the order’s client_order_id, so
a retried logical order deduplicates at the broker.Asset class differences
| Stocks | Crypto | Options | |
|---|---|---|---|
| Symbol | AAPL | BTC/USD | AAPL241213C00250000 |
| Order types | all | market, limit, stop_limit | all |
time_in_force | day, gtc, … | gtc, ioc | day, gtc |
| Hours | market + extended | 24/7 | market |
| Fractional | yes (notional/qty) | yes | no |
Crypto trading must be enabled on the user’s brokerage account (the crypto
agreement signed). Check
trading_account → crypto_status. Naive surfaces this
but does not toggle it — it’s an account-level setting on the brokerage.The brokerage enforces a $10 minimum per crypto order. An order below it is
rejected with a
forbidden error ("cost basis must be >= minimal amount of order 10") — the connection stays valid; just resize the order.Positions & orders
Market data
Governance
trading.order.create, trading.order.cancel, and trading.position.close are
in the default approval set. For a real end-user (not the operator’s own default
user), an agent (API-key) call returns 202 { "status": "pending_approval" }
and the action runs only after a human approves it in
Approvals. Operators can opt in/out per Account Kit
via primitives_config.trading.requiresApproval.
Connection statuses
| Status | Meaning |
|---|---|
pending | OAuth started, awaiting authorization |
active | Connected and ready to trade |
expired | The brokerage rejected the token (401) — reconnect |
failed | Token exchange failed |
DELETE /v1/trading/connections/:env) removes the stored
connection entirely; reconnecting creates a fresh one.
Configuration
The trading primitive requires the platform OAuth app credentials + an encryption key on the API:| Setting | Purpose |
|---|---|
| Brokerage OAuth app credentials | Client ID + secret for the platform’s brokerage OAuth app |
| OAuth redirect URI | Whitelisted callback (defaults to ${API_URL}/v1/trading/oauth/callback) |
| Encryption key | 64-char hex key used to encrypt stored tokens at rest |
Your brokerage OAuth app must be approved before it can execute live trades;
paper works for development.