Your first API call
Everything a trader does goes through the trading API on the same port as the cockpit.
This page assumes you have a trading token from
your first paper trade in
OMS_TRADING_TOKEN.
Authentication
Section titled “Authentication”Send the token as a bearer header:
curl -s localhost:3001/portfolios -H "Authorization: Bearer $OMS_TRADING_TOKEN"[{"portfolio_id":"4e33bc9e-52e0-4dc5-87a7-356d59ffc681","code":"main","name":"Main","status":"ACTIVE","base_currency":"USD","can_trade":true,"can_view":true,"can_allocate":false}]A token belongs to a principal. What it can see and trade comes from that principal’s
portfolio grants — can_view, can_trade, can_allocate per portfolio. It can never
reach /admin. Mint several tokens per principal to rotate them without re-permissioning.
The cockpit password is a different credential: it is for /admin and the cockpit only.
The calls you will use most
Section titled “The calls you will use most”| Call | What it does |
|---|---|
GET /portfolios |
Portfolios this token may act on |
GET /instruments?search=AAPL |
Search the catalog, best match first |
POST /orders/submit |
Place an order |
GET /orders |
Your blotter, newest first |
GET /orders/{id} |
One order’s current state |
GET /orders/{id}/events |
One order’s full history |
POST /orders/cancel |
Cancel an order |
GET /portfolios/{id}/positions |
Positions in a portfolio |
Every endpoint, with request and response schemas, is in the
API reference. A running server also serves its own spec at
/api-docs/openapi.json and an interactive explorer at /scalar.
Search, then submit
Section titled “Search, then submit”T="Authorization: Bearer $OMS_TRADING_TOKEN"
curl -s "localhost:3001/instruments?search=AAPL&limit=2" -H "$T"[{"id":14074,"symbol":"AAPL","name":"Apple Inc. Common Stock","venue":"XNAS","asset_class":"EQUITY","instrument_class":"SPOT","status":"ACTIVE","has_options":false}, {"id":11340,"symbol":"AAPB","name":"GraniteShares ETF Trust GraniteShares 2x Long AAPL Daily ETF","venue":"XNAS","asset_class":"EQUITY","instrument_class":"SPOT","status":"ACTIVE","has_options":false}]An order names its instrument either by instrument_id or by symbol (add
"venue": "XNAS", or write AAPL@XNAS, when a symbol exists on more than one venue).
limit_price is required for "order_type": "limit".
The blotter
Section titled “The blotter”curl -s "localhost:3001/orders?limit=5" -H "$T"[{"order_id":"36276e25-…","client_order_id":"first-trade","principal_code":"alice","portfolio_code":"main","broker_connection_code":"alpaca-paper","instrument_symbol":"AAPL","instrument_name":"Apple Inc. Common Stock","side":"buy","order_type":"market","status":"canceled","original_qty":1.0,"leaves_qty":1.0,"cum_qty":0.0,"avg_px":null,"created_at":"2026-10-29T06:32:01.923151Z","updated_at":"2026-10-29T06:32:02.050697Z"}]Python
Section titled “Python”The Python client wraps the same API:
pip install "git+https://github.com/maxkuttner/openoms#subdirectory=clients/python"import osimport time
from oms_client import OMS
oms = OMS("http://localhost:3001", token=os.environ["OMS_TRADING_TOKEN"])
pf = oms.portfolios()[0]oid = oms.submit(portfolio=pf.portfolio_id, symbol="AAPL", side="buy", quantity=1)time.sleep(1)print("submitted:", oms.order(oid).status)
print("cancel:", oms.cancel(oid))time.sleep(2)print("now:", oms.order(oid).status)submitted: routedcancel: pendingnow: canceledoms.cancel() returns "pending" when the cancel was forwarded to the broker (confirmed
asynchronously) and "canceled" when the OMS cancelled the order outright.
oms.wait_for(oid) blocks until an order reaches a final status — filled, canceled,
rejected or expired — and raises TimeoutError after 60 seconds otherwise, which is
what happens to an unfilled order outside market hours.