Skip to main content
The Trading primitive links a user’s brokerage account via an OAuth2 Connect flow. Each user authorizes their own brokerage account (paper and/or live); Naive performs the token exchange and proxies the brokerage’s trading API on their behalf — so you never touch OAuth plumbing, token storage, or per-user isolation. One primitive trades stocks, options, and crypto: the order 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.
1

Start the flow

Returns { "authorize_url": "https://<brokerage-oauth>/authorize?...", "env": "paper" }.
2

User authorizes

Open the authorize_url and approve access. The brokerage redirects to Naive’s callback (/v1/trading/oauth/callback), which stores the token.
3

Confirm and trade

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

ToolTypeDescription
trading_connectSetupStart the brokerage OAuth flow (returns an authorize URL)
trading_connectionsSetupList linked environments (paper/live) and status
trading_disconnectSetupForget a stored connection
trading_accountReadGet the connected brokerage account
trading_assetsReadList tradable assets (filter by asset class)
trading_positionsReadList open positions
trading_positionReadGet one open position
trading_ordersReadList orders
trading_get_orderReadGet one order
trading_quoteReadLatest quote(s) for symbols
trading_create_orderCore (sensitive)Place an order
trading_cancel_orderCore (sensitive)Cancel an open order
trading_close_positionCore (sensitive)Close (liquidate) a position

Placing orders

The same endpoint trades every asset class — the symbol selects the market. Provide either qty (shares/coins) or notional (dollar amount).
Via the API:

Order parameters

ParameterTypeDescription
symbolstringAsset symbol — AAPL, BTC/USD, or an OCC option symbol
sidestringbuy or sell
qtystringQuantity (shares/coins). Use qty or notional
notionalstringDollar amount (fractional). Use notional or qty
typestringmarket (default), limit, stop, stop_limit, trailing_stop
time_in_forcestringday, gtc, opg, cls, ioc, fok. Crypto supports gtc/ioc
limit_pricestringRequired for limit / stop_limit
stop_pricestringRequired for stop / stop_limit
order_classstringsimple, bracket, oco, oto (equities)
extended_hoursbooleanAllow execution during extended hours (equities)
envstringpaper 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

StocksCryptoOptions
SymbolAAPLBTC/USDAAPL241213C00250000
Order typesallmarket, limit, stop_limitall
time_in_forceday, gtc, …gtc, iocday, gtc
Hoursmarket + extended24/7market
Fractionalyes (notional/qty)yesno
Crypto trading must be enabled on the user’s brokerage account (the crypto agreement signed). Check trading_accountcrypto_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 account’s own default agent profile), an agent (API-key) call returns 202 { "status": "pending_approval" } and the action runs only after a human approves it in Approvals. AgentProfiles can opt in/out per Account Kit via primitives_config.trading.requiresApproval.

Connection statuses

StatusMeaning
pendingOAuth started, awaiting authorization
activeConnected and ready to trade
expiredThe brokerage rejected the token (401) — reconnect
failedToken exchange failed
Disconnecting (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:
SettingPurpose
Brokerage OAuth app credentialsClient ID + secret for the platform’s brokerage OAuth app
OAuth redirect URIWhitelisted callback (defaults to ${API_URL}/v1/trading/oauth/callback)
Encryption key64-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.