Skip to main content
A persona can connect its own brokerage account — paper or live — over OAuth. Once connected, the account can be read and traded from the API, and an agent whose session selects that persona gets trading tools whose orders each wait for a person’s approval. Naive Managed Agents is not a broker or an investment adviser and holds no customer money; it keeps one sealed access token per persona and env, which no response ever returns. Nothing Naive or an agent says about a symbol is investment advice. See Trading for the model and the agent tools. Every method takes the persona first (an idn_ id or its name). env is optional on the reads and writes: with one active connection it is implied, with both connected it is required (validation_failed on env). Money is integer micro-USD; quantities are decimal strings such as "0.0125". Writes need a key with the billing:write scope; reads take any key. Connecting a live account, and placing, canceling or closing on one, also needs a live sk_live_ key (forbidden otherwise).

connect

POST /v1/identities/{id}/trading/connect. Answers { object: "trading_connect", authorize_url, env, disclosure }. Show disclosure to the person before they open authorize_url. After they approve, the brokerage sends their browser to GET /v1/trading/oauth/callback, which forwards to the dashboard; there the signed-in person finishes with client.trading.complete({ state, code }) (POST /v1/trading/oauth/complete) and lands on the persona’s page with ?trading=connected (or ?trading=failed). Only a state minted in the caller’s own organization completes. The link works once and expires after 15 minutes. Reconnecting an active env keeps it active until the new authorization lands.

connections

GET /v1/identities/{id}/trading/connections. Both envs’ rows: status is pending, active, expired (the brokerage revoked access — connect again) or failed, with status_reason saying why.

disconnect

DELETE /v1/identities/{id}/trading/connections/{env}. Deletes the connection and its token.

account / positions

GET /v1/identities/{id}/trading/account answers cash_micro_usd, buying_power_micro_usd and equity_micro_usd. GET /v1/identities/{id}/trading/positions lists open positions; a crypto position’s symbol is written without a slash (BTCUSD).

orders / order

GET /v1/identities/{id}/trading/orders (default status: "open", limit 1–500, default 50) and GET /v1/identities/{id}/trading/orders/{order_id}. An order’s status is the brokerage’s own (new, filled, canceled, …).

quotes

GET /v1/identities/{id}/trading/quotes. The latest bid and ask for 1–100 symbols of one asset class (default us_equity). Crypto symbols are slashed: BTC/USD.

placeOrder

POST /v1/identities/{id}/trading/orders, answering 201. type (market, limit, stop, stop_limit) and time_in_force (day, gtc, ioc, fok, opg, cls) are required — there is no default. Give exactly one of qty or notional_micro_usd; limit_price_micro_usd is required on limit and stop_limit orders and refused on the others, and stop_price_micro_usd likewise on stop and stop_limit. The request’s Idempotency-Key becomes the order’s client_order_id unless the body names one. The client sends a new key on every call, so to make a retry safe, pass your own client_order_id: the brokerage refuses a second order with the same one. Venue rules — a minimum notional, which time-in-force a coin accepts — are the brokerage’s: a refusal comes back as validation_failed or forbidden with its reason.

cancelOrder

DELETE /v1/identities/{id}/trading/orders/{order_id}.

closePosition

POST /v1/identities/{id}/trading/positions/{symbol}/close. At most one of qty or percentage (greater than 0, at most 100); neither closes the whole position. Answers the closing order.

Errors