Skip to content
Start Trading

Changelog

Notable additions and changes to the Clear Street Trading API.

Interrupted Omni responses fail instead of hanging

A response interrupted by a service restart or failure now ends as failed with error.code execution_interrupted, usually within about 35 seconds. Its assistant message is errored, also with error.code execution_interrupted, and keeps any partial content. Previously such a response could stay running and block new messages in the thread. Send the message again to retry. All other failures keep error.code FAILED.

  • GET /v1/omni-ai/responses/{response_id}
  • GET /v1/omni-ai/threads/{thread_id}/response
  • GET /v1/omni-ai/threads/{thread_id}/messages
  • POST /v1/omni-ai/threads/{thread_id}/messages
  • DELETE /v1/omni-ai/responses/{response_id}

Negative max_notional rejected on account settings update

PATCH /v1/accounts/{account_id} accepted a negative risk.max_notional. A negative limit caused the risk check to reject every new order on the account. The endpoint now rejects a negative risk.max_notional with 400 Bad Request and does not change the account settings. A null value still clears the limit.

  • PATCH /v1/accounts/{account_id}

Omni messages sent during a response steer it

POST /v1/omni-ai/threads/{thread_id}/messages now accepts a message while another response in the thread is queued or running. It returns 200 with a new response_id. The new response has status queued. The endpoint no longer returns 409 for an active response. It still returns 409 when the thread scope changed or an Idempotency-Key was used for a different request.

Omni reads the new message at the next safe point of the running response. The running response then ends with status steered if it showed text, or merged if it showed no text. The response for the newest message continues the work and answers all messages sent so far. Earlier queued responses that it answers also end merged. Some requests, such as research, do not steer. Their responses, and the responses for messages sent after them, start in order after the earlier responses end.

Message outcome has two new values:

  • steered: the assistant message is complete as written. The user sent another message before it finished.
  • merged: the assistant message has no content. A later answer covers its turn. Hide this message.

GET /v1/omni-ai/threads/{thread_id}/response now returns the running response. When no response is running, it returns the next queued response. It returns data: null when the thread is idle.

DELETE /v1/omni-ai/responses/{response_id} on a running response also cancels the queued responses in that thread. On a queued response, it cancels only that response. On a response that ended steered or merged, it stops the response that continues its work, as for a running response. Each canceled response has a canceled assistant message.

Omni can also start a response the user did not send. When background work finishes, such as a subagent Omni started to look into a question, Omni answers it in the thread without a new user message. That response omits user_message_id, which is now optional on the response returned by GET /v1/omni-ai/responses/{response_id} and GET /v1/omni-ai/threads/{thread_id}/response; its absence means the response presents a background result, such as a subagent’s report. Its assistant message appears in the thread with no preceding user message. Typed SDK callers that read user_message_id as always present must handle it being absent.

This updates the existing 2025-10-31 contract; no API version change is required. To migrate:

  • Accept steered and merged in response status and message outcome. Treat an unknown response status as terminal.
  • When a response ends steered or merged, poll GET /v1/omni-ai/threads/{thread_id}/response at once for the response that continues the work.
  • To show every answer, including ones that start without a request, poll the thread response endpoint while the thread is open. Refresh messages when the response id changes or data becomes null.
  • POST /v1/omni-ai/threads/{thread_id}/messages
  • GET /v1/omni-ai/threads/{thread_id}/messages
  • GET /v1/omni-ai/messages/{message_id}
  • GET /v1/omni-ai/threads/{thread_id}/response
  • GET /v1/omni-ai/responses/{response_id}
  • DELETE /v1/omni-ai/responses/{response_id}

Locates, locate rates, and order preview endpoints released

The locate, locate rate, and order preview endpoints are now generally available. Before this release, the locate and locate rate endpoints were in beta, and the order preview endpoint was not in the public API.

Use the locate endpoints to read the locates for an account:

  • GET /v1/accounts/{account_id}/locates lists locates for one effective date. The date defaults to the current New York calendar date. Filter the list by status and by instrument ID or symbol.
  • GET /v1/accounts/{account_id}/locates/{id} returns one locate. The id matches the locate request ID, the locate ID, or the client request ID.

Use the locate rate endpoints to read the cached borrow rate for an instrument:

  • GET /v1/locates/rates/{instrument_id} returns the rate for one instrument. The endpoint returns 404 when the instrument is unknown or has no cached rate.
  • GET /v1/locates/rates returns rates for up to 1,000 instruments. The response has one row per requested instrument, in request order. Each row has either rate or error. The status is 200 when every instrument has a rate. The status is 207 when at least one row has an error.

Use the order preview endpoint to check an order before you submit it:

  • POST /v1/accounts/{account_id}/orders/preview evaluates every pre-trade risk check for each order. It projects the account balances and positions as if the order fills completely. The projection uses the limit price for limit orders and the current reference price for market orders. The endpoint does not submit orders and does not change the account.
  • The endpoint evaluates each order independently. An order does not see the projected fills of the other orders in the request.
  • The response has one result per order, in request order. When the request has more than one order, each order must have a unique id. The result echoes the id.
  • An order that cannot be previewed has an error on its own result. The other results are not affected, and the status is still 200. Request-level failures return a non-2xx status: 400 for an empty batch or a missing or duplicate id, 403, 422, and 503 when the engine is unavailable.
  • GET /v1/accounts/{account_id}/locates
  • GET /v1/accounts/{account_id}/locates/{id}
  • GET /v1/locates/rates
  • GET /v1/locates/rates/{instrument_id}
  • POST /v1/accounts/{account_id}/orders/preview

queue_state removed from orders

Orders no longer return the queue_state field. Use status instead:

  • QUEUED replaces queue_state: AWAITING_RELEASE for an order that waits for its scheduled release time.
  • PENDING_TRIGGER replaces queue_state: AWAITING_RELEASE for an order that waits for its trigger condition, for example a trailing stop.
  • Other open statuses replace queue_state: RELEASED.

releases_at is unchanged.

  • GET /v1/accounts/{account_id}/orders
  • GET /v1/accounts/{account_id}/orders/{order_id}
  • POST /v1/accounts/{account_id}/orders
  • PATCH /v1/accounts/{account_id}/orders/{order_id}
  • DELETE /v1/accounts/{account_id}/orders
  • DELETE /v1/accounts/{account_id}/orders/{order_id}
  • DELETE /v1/accounts/{account_id}/positions
  • DELETE /v1/accounts/{account_id}/positions/{instrument_id}

underlying_instrument_type added to option contracts

GET /v1/instruments/options/contracts now includes underlying_instrument_type alongside underlying_instrument_id. Use it to tell an index underlier from an equity underlier without a separate lookup.

The field is omitted when the contract’s underlier has not been resolved or its type is unavailable.

  • GET /v1/instruments/options/contracts

Expiry-day option opening orders restricted before session close

On the expiry day of a non-index option, Clear Street rejects an order that opens a position from 30 minutes before the regular options-session close until the end of that day. The cutoff is 3:30 pm Eastern Time on a normal session and 12:30 pm Eastern Time on a session that closes at 1:00 pm. Submit opening orders before the cutoff.

  • An order that closes or reduces an existing position stays allowed, subject to the other risk checks. A working closing order reserves closing capacity.
  • Clear Street rejects a multileg order as a whole when any leg opens an expiry-day non-index option position after the cutoff.
  • Index options are exempt and can open positions until their trading close. Options on exchange-traded funds, such as SPY, remain subject to the cutoff.
  • An option with a later expiry date is not affected.
  • The cutoff also applies to an order replacement.
  • An order that Clear Street accepted and routed before the cutoff is not canceled by this restriction and can execute after the cutoff.

Clear Street also rejects a multileg replacement, including a price-only replacement, when the reported cumulative fills of the legs do not match the strategy ratios. This check applies at all times, not only on an expiry day. The original order stays working. Retry the replacement after the matching fill reports arrive.

  • POST /v1/accounts/{account_id}/orders
  • PATCH /v1/accounts/{account_id}/orders/{order_id}

Fixed session open, high, and low for US equities

For US equities, the session open, high, and low were sometimes wrong or stale. These values now follow the session open, high, and low from the consolidated trade feed. Before the first trade of a session, the values are from the prior session. session.ohlv_date and trade_date identify the session of the values.

  • GET /v1/market-data/snapshot
  • GET /v1/market-data/daily-summary
  • POST /v1/screener

Higher house margin requirements for naked short options

Clear Street now applies a house margin floor to naked short options in Reg T margin accounts. A naked short call requires at least the premium plus 100% of the underlying market value multiplied by the underlier’s leverage factor. A naked short put requires at least the premium plus 50% of the strike value multiplied by that factor. The leverage factor does not multiply the premium. Where the standard Reg T requirement is higher, the higher requirement applies. Clear Street rejects an order that does not leave enough buying power under the new requirement.

The same requirements apply to the margin checks for a physically settled exercise and for a do-not-exercise instruction. Those checks also evaluate the account with no pending order filled, so a pending hedge cannot cover a deficit in that outcome. Review the margin impact before you submit an order or an instruction.

  • POST /v1/accounts/{account_id}/orders
  • PATCH /v1/accounts/{account_id}/orders/{order_id}
  • POST /v1/accounts/{account_id}/positions/instructions
  • FIX NewOrderSingle (35=D) and OrderCancelReplaceRequest (35=G)

Locates MCP tools

The get_locates and get_locate_by_id MCP tools return an account’s locates. They accept the same input and return the same results as GET /v1/accounts/{account_id}/locates and GET /v1/accounts/{account_id}/locates/{id}.

get_locates lists locates for one effective date, which defaults to today’s New York calendar date. Use the status and instrument_ids arguments to filter the list; each is a JSON array. get_locate_by_id takes a locate_id, which can be a locate request ID, a locate ID, or a client request ID.

Both tools take an optional account_id argument. It can be omitted when only one account is available. The tools are available on the read-only and trading MCP endpoints.

  • GET /v1/accounts/{account_id}/locates
  • GET /v1/accounts/{account_id}/locates/{id}

Earnings transcripts endpoint

GET /v1/instruments/{instrument_id}/earnings-transcripts returns earnings call transcripts for an instrument, newest fiscal period first. Each item has year, period (Q1 to Q4), period_type (always QUARTERLY), date (the call date), and content (the full transcript text).

page_size defaults to 1 and has a maximum of 5. A larger value is reduced to 5. The page_token does not keep your filters: send the same filters with every page request.

Filters:

  • year and period select a fiscal quarter.
  • event_date matches transcripts whose call date is within one day of an earnings event date.
  • date.gt, date.gte, date.lt, and date.lte filter the call date. See Range filters.

An unknown instrument returns 404. An instrument with no transcripts returns an empty list.

Each earnings event now has transcript_available. It is always present. When it is true, GET /v1/instruments/{instrument_id}/earnings-transcripts?event_date=<event date> returns the transcript.

  • GET /v1/instruments/{instrument_id}/earnings-transcripts
  • GET /v1/instruments/{instrument_id}/events
  • GET /v1/instruments/events

Estimated short rates MCP tool

The get_estimated_short_rates MCP tool returns estimated short (locate borrow) rates for one or more instruments. It accepts the same input and returns the same results as GET /v1/locates/rates. Use the instrument_ids argument to pass a JSON array of instrument IDs or symbols. The array can contain up to 1,000 entries.

The tool returns one row for each requested instrument, in request order. Each row contains either a rate or an error. The error is a 404 when the instrument is unknown or has no rate. Rates are estimates and can change intraday.

The tool is available on the read-only and trading MCP endpoints.

  • GET /v1/locates/rates

Shortable attribute on instruments

Adding shortable_attribute to the Instrument response. Possible values are EASY_TO_BORROW, HARD_TO_BORROW, or NOT_SHORTABLE. It is omitted for instruments that are not tradable equities.

When the value is NOT_SHORTABLE, not_shortable_reasons lists every reason that applies: INSUFFICIENT_LOCATE_INVENTORY or UNSUPPORTED_SECURITY (short selling is not supported for the security).

  • GET /v1/instruments
  • GET /v1/instruments/{instrument_id}
  • GET /v1/instruments/search
  • GET /v1/watchlists/{watchlist_id}

Option contracts accept a root parameter, underlier deprecated

GET /v1/instruments/options/contracts accepts a new root query parameter. It has the same behavior as underlier.

The underlier query parameter is deprecated and will be removed in a future release. Use root instead.

If you send both root and underlier, the values must be the same. If they differ, the request fails with a 400 error.

The get_option_contracts MCP tool now shows root. The tool still accepts underlier.

  • GET /v1/instruments/options/contracts

Overnight margin on balances and order previews

The margin_details object of the balances response gains two fields:

  • overnight_margin_requirement: the equity required to hold current positions overnight.
  • overnight_margin_excess: equity minus overnight_margin_requirement.

Each top_contributors entry gains overnight_margin_requirement for its underlying.

The margin_details object of an order preview gains overnight_margin_requirement and overnight_margin_excess, each with before, after, and change values.

  • GET /v1/accounts/{account_id}/balances
  • POST /v1/accounts/{account_id}/orders/preview

Omni entitlement list and delete deprecated

Two Omni AI entitlement endpoints are deprecated. They still work.

  • GET /v1/omni-ai/entitlements lists explicit grants only, so it omits accounts that are enabled by default. Use GET /v1/omni-ai/entitlement-status instead.
  • DELETE /v1/omni-ai/entitlements/{entitlement_id} revokes one grant by id. Use POST /v1/omni-ai/entitlements/opt-out instead.
  • GET /v1/omni-ai/entitlements
  • DELETE /v1/omni-ai/entitlements/{entitlement_id}

Omni entitlement status and opt-out

You can now read and turn off Omni AI entitlements for each account.

  • GET /v1/omni-ai/entitlement-status returns one entry for each account and entitlement code. Each entry has account_id, entitlement_code, and enabled. An account with no recorded choice has enabled set to true. Use the optional account_id query parameter to get one account. Without it, the response covers every account that the caller can access.
  • POST /v1/omni-ai/entitlements/opt-out turns off the entitlements in entitlement_codes for the accounts in account_ids. The response returns the resulting status for each requested account. The request is idempotent: an account that is already opted out stays opted out.

To turn an entitlement on again, sign the agreement with POST /v1/omni-ai/entitlements.

Both endpoints return 403 if the caller cannot access a requested account.

  • GET /v1/omni-ai/entitlement-status
  • POST /v1/omni-ai/entitlements/opt-out

Fixed missing executions for replaced orders

GET /v1/accounts/{account_id}/executions did not return a fill when the order was replaced before the fill occurred. It also did not return a fill that occurred while a cancel request for the order was pending. The endpoint now returns these fills, including fills from before this fix. The order’s filled_quantity and average_fill_price were always correct. Non-breaking.

  • GET /v1/accounts/{account_id}/executions

Market data snapshot temporarily withholds implied volatility

GET /v1/market-data/snapshot temporarily withholds implied volatility for options. The greeks.iv field stays in the response, but its value is always 0. A 0 value is not a market implied volatility.

All other greeks fields are unchanged.

If your integration reads greeks.iv, do not use it until the value returns. We expect greeks.iv to return next week with an improved calculation. We will announce the change in this changelog.

  • GET /v1/market-data/snapshot

Active option contracts found by exact match

Some option contracts have an active listing and an inactive listing with the same Options Symbology Initiative (OSI) symbol. For these contracts:

  • An exact OSI symbol search now returns the active contract. Before this fix, the search could return no results.
  • An exact option contract match (underlier, right, strike, and expiry date) is no longer reported as ambiguous.

Instrument search does not return inactive option contracts, also when include_inactive is true. include_inactive still applies to other asset classes.

  • GET /v1/instruments/search

FIX OpenClose (77) is checked against your position

Clear Street now checks OpenClose (77) on NewOrderSingle (35=D). If 77=O or 77=C differs from the position effect that Clear Street determines from your account’s position and open orders, Clear Street rejects the order with an Execution Report (39=8).

Before this change, OpenClose (77) was advisory. Clear Street replaced a value that did not agree with your position and accepted the order.

To keep the previous behavior, omit OpenClose (77). Clear Street then determines the position effect.

  • FIX NewOrderSingle (35=D)

Economic calendar MCP tool

The get_economic_events MCP tool returns macroeconomic calendar events, such as CPI releases, jobs reports, and central bank rate decisions. It accepts the same filters and applies the same defaults as GET /v1/calendars/economic-events: country, impact, timestamp.gt, timestamp.gte, timestamp.lt, timestamp.lte, page_size, and page_token.

The tool is available on the read-only and trading MCP endpoints.

  • GET /v1/calendars/economic-events

IPO events report offering_amount

IPO events now include the offering_amount field. It is the maximum aggregate offering value: all offered shares, including over-allotment (greenshoe) shares, multiplied by the top of the price range. The value is an upper bound. It assumes full exercise of the over-allotment option and pricing at the top of the range.

The market_cap field on IPO events is deprecated. It returns the same value as offering_amount. It is the offering amount, not a market capitalization. Change your integration to read offering_amount.

  • GET /v1/instruments/{instrument_id}/events
  • GET /v1/instruments/events

Market data snapshot supports targeting a full option chain

GET /v1/market-data/snapshot accepts a new targeting mode: underlying_instrument_id + expiry, provided together in place of instrument_ids. This resolves the underlier’s option chain for that expiry and returns a snapshot row for every contract in it. There is no cap on the number of contracts returned this way (the existing 100-id cap still applies to instrument_ids).

underlying_instrument_id and expiry must be provided together, and are mutually exclusive with instrument_ids; providing an incomplete pair or mixing modes returns 400.

  • GET /v1/market-data/snapshot

Omni threads ordered by latest activity

The thread list now returns the most recently active threads first, not the most recently created threads. A thread is active when it gets a new message or when the thread changes. updated_at now records the time of the last activity, so a new message also moves updated_at.

If your client shows threads in creation order, sort each page by created_at. A thread that gets a message while you page through the list moves to the first page, so a later page can skip that thread or show it again.

  • GET /v1/omni-ai/threads
  • GET /v1/omni-ai/threads/{thread_id}

Order execution strategy DMA

Order submissions accept strategy type DMA (Direct Market Access), which routes the order straight to a venue. destination is required and names the venue. Orders placed with DMA report {"type": "DMA", "destination": ...} in responses.

DMA is supported only on LIMIT orders with DAY time-in-force — narrower than VWAP and TWAP, which also accept MARKET. Like every non-SOR strategy, DMA is rejected on OTC common-stock orders.

DMA does not accept a start_at/end_at timing window.

  • POST /v1/accounts/{account_id}/orders
  • GET /v1/accounts/{account_id}/orders
  • GET /v1/accounts/{account_id}/orders/{order_id}

Private-market instruments

Instrument endpoints can now return private-market (unlisted) instruments. A private-market instrument carries a private-market symbol: uppercase letters and digits with _, ., or - separators, for example DATABRICKS_PVT. Its security_ids report the symbol with the new security_id_source value PRIVATE.

Every parameter that accepts a symbol also accepts a private-market symbol, including the {instrument_id} path parameter and comma-separated instrument_ids query parameters.

  • GET /v1/instruments
  • GET /v1/instruments/{instrument_id}

Economic calendar events endpoint

GET /v1/calendars/economic-events returns macroeconomic calendar events, such as CPI releases, jobs reports, and central bank rate decisions.

Filter by country (ISO 3166-1 alpha-2 code, or EU; defaults to US), impact (NONE, LOW, MEDIUM, HIGH), and timestamp (timestamp.gt, timestamp.gte, timestamp.lt, timestamp.lte). Absent an explicit timestamp lower bound, results default to events from the start of the previous trading day; absent an upper bound, results default through 7 days out.

Each event reports previous, estimate, actual, change, and change_percentage as numeric strings, omitted when the provider has no value. estimate and actual are frequently absent for minor releases, speeches, and holidays; a null actual before the print is expected, not missing data.

  • GET /v1/calendars/economic-events

Range filters for order list updated_at

You can now filter GET /v1/accounts/{account_id}/orders by last-update time using updated_at.gt, updated_at.gte, updated_at.lt, and updated_at.lte. Each parameter accepts an RFC3339 datetime (for example 2025-04-24T14:30:00Z) or a bare YYYY-MM-DD date. A bare date expands to a whole-day boundary: gte/lt expand to the start of that day, gt/lte expand to the end of that day. Combine a lower and upper bound to filter a window. A request whose resolved lower bound is strictly after its resolved upper bound now returns 400. See the Range filters guide for details.

  • GET /v1/accounts/{account_id}/orders

Attach widget context to Omni messages

Instant-chat thread and message requests now accept optional context. Attach up to four widget snapshots with a kind, label, optional captured_at, and JSON object data. Use strings for exact decimals and large identifiers. The complete context must fit within 64 KiB of compact JSON.

Message reads return the saved context separately from visible message content. The field is omitted when the user supplied no context. Context is stored with the message that carries it and remains available in conversation history. Reusing an idempotency key with different context returns a conflict.

  • POST /v1/omni-ai/threads
  • POST /v1/omni-ai/threads/{thread_id}/messages
  • GET /v1/omni-ai/threads/{thread_id}/messages
  • GET /v1/omni-ai/messages/{message_id}

FIX API for order entry

Clear Street now supports order entry over the Financial Information eXchange (FIX) protocol, version 4.2. Connect your order management system to a FIX session to submit, cancel, and replace US-equity orders. Orders submitted over FIX flow into the same trading platform as orders submitted through the REST API — the same accounts and risk checks.

Fixed incorrect close price on some ex-dividend dates

GET /v1/market-data/snapshot’s session.previous_close and session.change could be wrong for some instruments on an ex-dividend date. GET /v1/screener’s prev_day_close could show the same issue. Both now reflect the corrected price. Non-breaking.

  • GET /v1/market-data/snapshot
  • GET /v1/screener

Order execution strategies SOR, VWAP, and TWAP

Order submissions accept an optional strategy field: SOR (default), VWAP, or TWAP. Each order reports its strategy in responses, except orders placed before this release, which report no strategy. OTC common-stock orders report {"type": "SOR"}, since SOR is the only strategy they support.

SOR does not accept urgency; a value in the request is ignored.

VWAP and TWAP accept an optional start_at/end_at timing window (RFC 3339 UTC timestamps); SOR does not. min_percent and max_percent are not yet supported; requests carrying them are ignored, not rejected.

SOR is supported on all order types and time-in-force values, including OTC common-stock orders. VWAP and TWAP are supported only on MARKET and LIMIT orders with DAY time-in-force. An OTC common-stock order submitted with VWAP or TWAP is rejected.

A request returns a 400 when:

  • strategy.type is SOR and it sets start_at or end_at.
  • end_at is at or before start_at.
  • end_at is in the past.
  • end_at is after the close of regular market hours.
  • start_at is more than 30 seconds in the past.
  • strategy.type is VWAP or TWAP and it sets urgency.
  • strategy.type is VWAP or TWAP and the order has extended_hours: true.
  • strategy is set to VWAP or TWAP on an order that is not MARKET/LIMIT with DAY time-in-force.

A request returns a 422 when strategy.type is AP, POV, or DARK — these strategies are not yet supported.

POST /v1/accounts/{account_id}/orders now validates order shape before submission: an invalid quantity (zero or negative) or an invalid price for the order type now returns a 400 immediately. Previously, the order was accepted and then rejected asynchronously.

PATCH does not change an order’s strategy. A strategy key in a PATCH request body is ignored.

  • POST /v1/accounts/{account_id}/orders
  • GET /v1/accounts/{account_id}/orders
  • GET /v1/accounts/{account_id}/orders/{order_id}
  • PATCH /v1/accounts/{account_id}/orders/{order_id}

Start Omni conversations without an account

Active API version 2025-10-31 now lets authenticated users start and use Omni conversations without a trading account. Omit account_id when no account is selected. JSON request bodies also accept null as omission. Omit query parameters instead of sending an empty value or null.

The first accepted message with a selected account links that account to the thread. The link does not change when the client selects another account. Start a new thread to use another account.

Pass the selected account_id to GET /omni-ai/threads to list only your conversations linked to that account. Omit it to list only your currently unlinked conversations. Linking a thread moves it from the unlinked list into that account’s list.

Resource requests authorize the thread’s linked account, even when account_id is omitted or another account is selected. Revoked account access denies resource requests and requests to list that account’s conversations.

This updates the existing 2025-10-31 contract; no API version change is required. A concurrent account link can return 409; refresh the thread before retrying. Reuse an idempotency key only for the original request.

  • POST /v1/omni-ai/threads
  • GET /v1/omni-ai/threads
  • GET /v1/omni-ai/threads/{thread_id}
  • POST /v1/omni-ai/threads/{thread_id}/messages
  • GET /v1/omni-ai/threads/{thread_id}/messages
  • GET /v1/omni-ai/threads/{thread_id}/response
  • GET /v1/omni-ai/messages/{message_id}
  • GET /v1/omni-ai/responses/{response_id}
  • DELETE /v1/omni-ai/responses/{response_id}
  • POST /v1/omni-ai/messages/{message_id}/feedback

Daily summary endpoint deprecated

GET /v1/market-data/daily-summary is deprecated and will be removed in a future release. Use GET /v1/market-data/snapshot instead, which now reports the same open, high, low, volume, and open-interest fields under session and top-level open_interest. The top-level cumulative_volume field on snapshots is also deprecated; use session.cumulative_volume.

The get_market_data_daily_summary MCP tool is removed. Use get_market_data_snapshot instead.

  • GET /v1/market-data/daily-summary
  • GET /v1/market-data/snapshot

Eligible-only last trade in market data

last_trade, change, and change_percent in a market data snapshot now reflect only a last-sale-eligible or last-trade-eligible print. An odd-lot or out-of-sequence print no longer appears as last_trade. When the most recent known print is ineligible, the snapshot omits last_trade, change, and change_percent instead of showing that print’s price.

The instrument screener’s price field follows the same rule: it now falls back to the previous close when the cached trade is ineligible.

  • GET /v1/market-data/snapshot
  • GET /v1/screener
  • POST /v1/screener

Live Rule 201 short sale state on market data snapshots

GET /v1/market-data/snapshot now returns short_sale_restricted, the live SEC Rule 201 short sale price test state for each security, sourced from the trading status feed.

"short_sale_restricted": true

The field is always present, and is one of:

  • true - the price test is in force, so non-exempt short sales at or below the national best bid will be rejected by the venue.
  • false - a trading status was received and the price test is not in force.
  • null - we have no reading, either because no trading status has been seen for this security yet, or because Rule 201 does not cover this security type. Options, indices and other non-equity instruments are always null.

null is not the same as false. Treat it as a prompt to check another source before shorting, not as confirmation that the security is clear.

The field reports the current state only, with no timestamps. Rule 201 is a live signal, so poll it again rather than trying to work out when a restriction lapses: a security still restricted the next day continues to report true, and one whose restriction has lapsed reports false.

Rule 201 is a live circuit breaker. It triggers intraday when a security falls 10% below its previous close, and lapses after the following trading day. It is distinct from is_short_prohibited on the instrument endpoints, which is a standing property of the security and does not change during the session.

  • GET /v1/market-data/snapshot

Machine-readable rejection codes on position instructions, business rejections now 422

Rejected position instructions now carry a machine-readable rejection object. Each rejection has a stable reason code (for example DNE_NOT_ON_EXPIRY, INSUFFICIENT_POSITION, OPTIONS_LEVEL_EXCEEDED, or EXERCISE_PAST_CUTOFF), a domain, a human-readable description, and a metadata map of reason-specific parameters (for example available and requested, or expiry and business_date), typed as a string-to-string map. Branch on rejection.reason and render rejection.description. The same rejection is returned when reading instructions (GET) as well as on submit and cancel, so a rejected instruction looks the same however you fetch it. It is present on every rejected row (accepted rows carry none); rows rejected before structured codes existed surface a generic REJECTED reason with the original message in description.

The HTTP status for a rejected instruction now reflects the specific cause. A well-formed instruction that is rejected on its merits — for example an exercise after expiry day, a do-not-exercise or contrary-exercise outside expiry day, insufficient position, an options-level limit, or a clearing rejection — now returns 422 Unprocessable Entity. This applies to a submission where every row is rejected for such a reason, and to a cancel that arrives too late or targets a terminal instruction. These cases previously returned 400 Bad Request. Duplicate (409), clearing-unavailable (503), and internal-fault (500) responses are unchanged. If your client keys on 400 to detect these rejections, update it to handle 422.

  • POST /v1/accounts/{account_id}/positions/instructions
  • DELETE /v1/accounts/{account_id}/positions/instructions/{instruction_id}
  • GET /v1/accounts/{account_id}/positions/instructions

More accurate previous close in screener and fundamentals

GET /v1/screener’s prev_day_close and GET /v1/instruments/{instrument_id}/fundamentals’s previous_close now resolve from the same close-price source as the rest of the platform, instead of a separate end-of-day feed anchored to a single global trade date.

Two effects follow from this. First, an instrument now reports its own most recent close even when it lags behind other instruments’ trade dates; previously this case returned no value. Second, an admin close-price correction or a corporate-action adjustment now appears in these fields, matching what other instrument endpoints already report.

Percent-change and 52-week gap fields (one_week_change_pct through one_year_change_pct, gap_from_52w_high_pct, gap_from_52w_low_pct) are unaffected and continue to compute from the prior close-price source.

  • GET /v1/screener
  • GET /v1/instruments/{instrument_id}/fundamentals

Snapshots add session OHLV and open interest

GET /v1/market-data/snapshot now reports the same open, high, low, volume, and open-interest fields previously available only from GET /v1/market-data/daily-summary:

  • session.open, session.high, session.low, and session.ohlv_date: the most recent session’s open/high/low prices and the date they apply to.
  • session.cumulative_volume: cumulative traded volume for the current session. Prefer this over the top-level cumulative_volume field, which is now deprecated.
  • session.ohlv_applicable: false for index instruments, whose price is a computed level rather than a traded security. When false, the OHLV fields above are always absent.
  • open_interest: open interest (outstanding contracts), populated for options only.

session is now always present in the response; each field inside it is independently nullable and omitted when absent.

GET /v1/market-data/snapshot now accepts at most 100 instrument_ids per request.

  • GET /v1/market-data/snapshot

Tick rules on instruments and options contracts

Instruments and options contracts now carry a tick_rules array describing the price increments the instrument can be quoted and traded in. Use it to constrain a limit price before you submit, instead of discovering the constraint from an INVALID_TICK_SIZE rejection.

The minimum increment depends on price, so the response returns the bands rather than a single current value. start_price is inclusive and end_price is exclusive, so every price falls in exactly one band. The last band has no end_price and runs without an upper bound. A price is valid when it is a whole multiple of that band’s tick_size.

A non-penny index option looks like this:

"tick_rules": [
{ "start_price": "0", "end_price": "3.0", "tick_size": "0.05" },
{ "start_price": "3.0", "tick_size": "0.10" }
]

The bands describe the instrument itself. On an equity they say nothing about that equity’s option chain, so read them from the contract you intend to trade.

tick_rules is absent when no schedule is available. That covers instruments we publish no schedule for, such as bonds and futures, and options whose penny-program status our reference data does not supply. Treat an absent field as unknown rather than unrestricted.

  • GET /v1/instruments
  • GET /v1/instruments/{instrument_id}
  • GET /v1/instruments/options/contracts

underlying_instrument_type added to positions, orders, and executions

GET /v1/positions, order responses, and execution responses now include underlying_instrument_type alongside underlying_instrument_id. Use it to tell an index underlier from an equity underlier without a separate lookup.

The field is null when the position, order, or execution is not an option, or when the underlier has not been resolved.

  • GET /v1/positions
  • GET /v1/orders
  • GET /v1/orders/{order_id}
  • POST /v1/orders
  • PATCH /v1/orders/{order_id}
  • DELETE /v1/orders/{order_id}
  • GET /v1/executions

AM-settled expiry dates follow the last trade cutoff

In the instrument endpoint’s option-expiry listing (include_options_expiry_dates=true), has_settles_on_open now counts only AM-settled contracts that you can still trade. AM-settled contracts stop trading at the close of the business day before settlement, so the flag becomes false before the expiry date arrives. Previously it stayed true until the date passed.

An expiry date is removed from options_contract_expiry_dates and from the deprecated options_expiry_dates field when no contract on that date can be traded in either settlement cycle. A date can therefore leave the response during a trading session. Request the listing again instead of caching it for the session.

has_settles_on_close is unchanged.

  • GET /v1/instruments/{instrument_id}

Account holder entity kind on accounts

Accounts now report account_holder_entity_kind, which tells you whether the account holder is a person or an organization. The field is always present and is one of:

  • NATURAL_PERSON — the account holder is a person.
  • LEGAL_ENTITY — the account holder is a corporation, partnership, LLC, trust, or fund.
  • OTHER — the account holder is neither, such as a joint or custody UGMA holder.
  • GET /v1/accounts
  • GET /v1/accounts/{account_id}

Market data endpoints report per-id resolution failures

GET /v1/market-data/snapshot and GET /v1/market-data/daily-summary now report which instrument_ids failed to resolve, instead of either failing the whole request or returning a null row.

  • If every requested id resolves, the response is unchanged: 200 with a full data array.
  • If some ids resolve and some do not, the response is 207 with data containing only the resolved instruments, and error set to a message and a structured details list of the failed ids (each entry has an instrument_id field).
  • If no id resolves, the response is 404 with the same error shape and no data.

Previously, GET /v1/market-data/snapshot returned 404 for the whole request if any single id failed to resolve. GET /v1/market-data/daily-summary returned 200 with a row with symbol and every market-data field null for each unresolved id; those rows are no longer returned — unresolved ids are reported in error instead.

  • GET /v1/market-data/snapshot
  • GET /v1/market-data/daily-summary

Overnight session added to market hours

The today_sessions and next_sessions objects returned by GET /v1/market-hours now include an overnight field. This field reports the overnight trading session for the US Equities market: the period from 20:00 ET on the prior evening through 04:00 ET the next morning.

The field follows the same structure as pre_market, regular, and after_hours. It is omitted when no overnight session is available for the requested date (for example, on holidays or for markets that do not support overnight trading).

The status.is_open field is true during the overnight session. The status.current_session field returns "overnight" during this period. The MarketSessionType enum now includes "overnight" as a possible value.

  • GET /v1/market-hours

Partial updates for saved screeners

PATCH /v1/saved-screeners/{screener_id} partially updates a saved screener. Every field is optional.

  • Omitting a field, or sending it as null, leaves the stored value unchanged.
  • Sending a field’s empty value clears it: columns: [] clears the stored columns, sorts: [] clears the stored sort, and filters: [] clears the stored filters.
  • name has no empty value that clears it. name: "" is rejected.
  • shared has no empty value either. shared: false sets it to false; it does not clear anything.
  • Unknown fields are rejected with a 422.

PUT /v1/saved-screeners/{screener_id} is now deprecated. Use PATCH instead. PUT still replaces the full screener configuration: an omitted columns, filters, or sorts field is cleared, not preserved. PUT’s behavior has not changed.

  • PATCH /v1/saved-screeners/{screener_id}
  • PUT /v1/saved-screeners/{screener_id} (deprecated)

Total count removed from news and financial statements

total_items and total_pages are no longer returned in the metadata of the four indicated as affected endpoints.

Use next_page_token to detect whether more results exist. Request the next page while next_page_token is present; stop when it is absent.

  • GET /v1/news
  • GET /v1/instruments/{instrument_id}/income-statements
  • GET /v1/instruments/{instrument_id}/balance-sheets
  • GET /v1/instruments/{instrument_id}/cash-flow-statements

Auction time-in-force values renamed to AT_OPEN and AT_CLOSE

The time_in_force values that select the opening and closing auctions have been shortened to AT_OPEN and AT_CLOSE.

  • Responses report AT_OPEN and AT_CLOSE; the previous AT_THE_OPENING and AT_THE_CLOSE are no longer returned, and the schema documents only the short values.
  • Submissions still accept AT_THE_OPENING and AT_THE_CLOSE as deprecated aliases, so existing integrations keep working. Move to the short values — the aliases will be removed in a future release.
  • POST /v1/accounts/{account_id}/orders
  • GET /v1/accounts/{account_id}/orders
  • GET /v1/accounts/{account_id}/orders/{order_id}

Position instructions: instruction_id renamed to client_instruction_id

The caller-supplied idempotency key on position instructions has been renamed from instruction_id to client_instruction_id, on both the submit request body and the instruction response. Update any requests and response parsing that use the old name.

A submit request that still sends the legacy instruction_id field now returns 400 Bad Request with a migration message, instead of silently ignoring the field and generating a server-side id in its place. The cancel path parameter {instruction_id} is unchanged; it is the server-assigned instruction id, not the caller-supplied key.

  • POST /v1/accounts/{account_id}/positions/instructions
  • GET /v1/accounts/{account_id}/positions/instructions
  • DELETE /v1/accounts/{account_id}/positions/instructions/{instruction_id}

Queued and PendingTrigger order statuses

Order status can now return two new values:

  • QUEUED — accepted by Clear Street and waiting for its scheduled release time.
  • PENDING_TRIGGER — accepted by Clear Street and held until its trigger condition is met, for example a trailing stop that has not yet been hit.

Both previously reported PENDING_NEW, so telling a held order apart from one already sent to the market meant reading queue_state. Orders held from a prior session now also report the correct status once they are loaded back.

queue_state is unchanged and still returned. It does not distinguish a scheduled release from a strategy trigger, so prefer status.

If you parse status into a fixed set of values, add the two new ones.

  • GET /v1/accounts/{account_id}/orders
  • GET /v1/accounts/{account_id}/orders/{order_id}
  • POST /v1/accounts/{account_id}/orders
  • PATCH /v1/accounts/{account_id}/orders/{order_id}
  • DELETE /v1/accounts/{account_id}/orders/{order_id}

Underlying instrument on position instructions, and a filter for it

Position instructions now include the option’s underlying_instrument_id on every response — list, submit, and cancel. The field is the identifier of the option’s underlying instrument, or null when the underlier is not available.

The list endpoint accepts a new underlying_instrument_id query parameter — an instrument id (UUID) or symbol — that returns only instructions whose contract has that underlier. It combines with the existing instrument_id filter as a logical AND.

  • GET /v1/accounts/{account_id}/positions/instructions
  • POST /v1/accounts/{account_id}/positions/instructions
  • DELETE /v1/accounts/{account_id}/positions/instructions/{instruction_id}

Option contracts: lookup by ID and settlement cycle filter

The options contracts endpoint accepts two new query parameters:

  • contract_ids — a comma-separated list of up to 100 instrument IDs or OSI option symbols — fetches specific contracts directly instead of listing a whole underlier’s chain. It’s mutually exclusive with underlier and underlying_instrument_id; unresolvable IDs are dropped rather than erroring.
  • is_settle_on_open — true returns only early-settling (AM, settle-on-open) contracts, false returns normal (PM) contracts, and omitting it returns both. Contracts with no recorded settlement cycle are treated as PM.
  • GET /v1/instruments/options/contracts

Options expiry dates split by settlement cycle

The instrument endpoint’s option-expiry listing (include_options_expiry_dates=true) now returns options_contract_expiry_dates, an array of {date, has_settles_on_open, has_settles_on_close} entries showing which expiry dates have AM-settled (“settle on open”) vs. PM-settled (“settle on close”) contracts. The existing options_expiry_dates field is deprecated in favor of it; it’s unchanged in shape and still returns the union of both settlement cycles.

  • GET /v1/instruments/{instrument_id}

Order side reduced to BUY/SELL; single orders accept position_intent

The order side contract is BUY / SELL across all submission paths, and single-order submissions accept a new optional position_intent field.

  • SELL_SHORT is no longer accepted as a request side on any submission path; submitting it returns a 400.
  • Responses report short sells as SELL; other legacy sides (for example CROSS / UNDISCLOSED) are reported as OTHER. The schema documents only BUY and SELL.
  • A new optional position_intent field (OPEN / CLOSE) is accepted on single-order submissions. When present it specifies the intended position effect; when omitted, the position effect is determined automatically. There is no response change.
  • The omni OrderSide value SELL_SHORT has been removed. Short-sale orders placed through Omni now use SELL as their side.
  • POST /v1/accounts/{account_id}/orders
  • GET /v1/accounts/{account_id}/orders
  • DELETE /v1/accounts/{account_id}/orders (cancel-all side filter)
  • PUT /v1/accounts/{account_id}/orders/{order_id}

Order/underlier filters and venue on executions

The executions endpoint accepts two new query parameters: order_ids, a comma-separated set matching an execution’s engine or client order ID, and underlying_instrument_ids, a comma-separated set of instrument IDs or symbols (index aliases like SPX/SPXW expand automatically) that matches option fills by their resolved underlier. Each execution also gains optional venue and underlying_instrument_id fields.

  • GET /v1/accounts/{account_id}/executions

Screener field catalog endpoint

The Trading API now exposes a screener field catalog. GET /v1/screener/catalog returns the fields you can screen on (with their kinds, value types, periods, and lookbacks), the enum universes for enum-valued fields, the operators allowed for each value type, and the built-in date variables and modifiers usable in filter right values. It also lists the default response fields for POST /v1/screener.

Field references in POST /v1/screener requests are validated against this catalog, so clients can use it to compose valid screens.

  • GET /v1/screener/catalog

Shared saved screeners

Saved screeners accept a new shared field. It is optional on create and update; omitting it leaves the current value unchanged (a newly created screener defaults to false). When a screener is shared: true, any user may fetch it by id. Saved screeners still only appear in the list response to their owner.

  • POST /v1/saved-screeners
  • GET /v1/saved-screeners
  • GET /v1/saved-screeners/{screener_id}
  • PUT /v1/saved-screeners/{screener_id}

Snapshot change percent rounded to 6 decimal places

The change_percent field in the market-data snapshot session object is now rounded to 6 decimal places.

  • GET /v1/market-data/snapshot

Venue MICs and timestamps added to market data snapshots

GET /v1/market-data/snapshot now reports the venue and exchange timestamp behind each snapshot’s last quote and last trade:

  • last_quote gains bid_venue and ask_venue — the ISO 10383 Market Identifier Code (MIC) of the venue currently holding the national best bid and best offer (NBBO). Each is omitted when that side carries no venue.
  • last_quote gains bid_timestamp and ask_timestamp — the exchange time the best bid and best ask were set. Each is omitted when that side carries no timestamp.
  • last_trade gains venue — the MIC of the venue where the last-sale trade took place — and timestamp — the exchange time of the trade. Index levels are computed rather than traded: they have no venue, and their timestamp is the time the index level was computed.
  • GET /v1/market-data/snapshot

Snapshot session adds unadjusted previous close field

Market-data snapshots add a new optional session.previous_close_unadjusted field carrying the raw previous session close, present only when a corporate-action adjustment (stock dividends, cash dividends, and forward/reverse splits) exists for the previous close date. The existing session.previous_close, session.change, and session.change_percent fields are unchanged: previous_close remains the corporate-action-adjusted close when an adjustment exists for the previous close date and the raw close otherwise, and change/change_percent remain relative to it. This release also corrects the schema examples and field documentation to match that contract. Non-breaking.

  • GET /v1/market-data/snapshot

Deprecated day-trade and total P&L fields removed from balances

The following long-deprecated fields have been removed from the balances response:

  • daily_total_pnl — use daily_pnl instead. The two have always carried the same value; daily_total_pnl existed only to give clients time to migrate.

  • The start-of-day day_trade_buying_power field.

  • The day_trade_buying_power_usage, day_trade_count, and pattern_day_trader fields on margin_details.

  • The day_trade_buying_power_usage field on each margin top-contributor entry.

    The day-trade fields are no longer relevant after FINRA and the SEC removed the pattern-day-trader concept.

  • GET /v1/accounts/{account_id}/balances

Clearer order rejection reasons

Orders rejected by pre-trade risk checks now report plain-English reasons — for example, “Insufficient buying power” instead of “Buying Power: required > available”. The machine-readable codes were also revised: SUB_PENNY is now INVALID_TICK_SIZE, SSR_UPTICK was retired, and LIQUIDATION_ONLY was split into INSTRUMENT_LIQUIDATION_ONLY and ACCOUNT_LIQUIDATION_ONLY. Avoid matching on the human-readable text.

  • POST /v1/accounts/{account_id}/orders
  • GET /v1/accounts/{account_id}/orders/{order_id}

Event defaults anchored to the next trading day

When listing instrument events on a weekend or US market holiday, the default from/to date window is now resolved against the next trading day rather than the calendar date, so upcoming-event queries made over a weekend cover the next session.

  • GET /v1/instruments/events
  • GET /v1/instruments/{instrument_id}/events

Underlier populated for index-option contracts

underlying_instrument_id is now populated on option contracts whose underlier is an index; it was previously null for these contracts.

  • GET /v1/instruments/options/contracts

Account-holder details on Get Account

GET /v1/accounts/{account_id} now returns an enriched account object with the account holder’s reference details. Four new fields are included, each nullable and null when the information is not on file or reference data is unavailable:

  • mailing_address — a structured address (line1, line2, city, state, postal_code, country).
  • date_of_birth
  • phone_number
  • country_of_tax_residency

Existing fields are unchanged; the additions are purely additive.

  • GET /v1/accounts/{account_id}

Instrument fields removed; time-in-force locked on replace

Two removals to be aware of:

  • The long-deprecated expiry and strike_price fields (which had been returning null since 2026-06-17) have been removed from the instrument response. Read option contract details from the options endpoints instead.
  • time_in_force has been removed from the replace-order request body. Time in force can no longer be changed when replacing an order — submit a new order if you need a different TIF.
  • GET /v1/instruments
  • GET /v1/instruments/{instrument_id}
  • PATCH /v1/accounts/{account_id}/orders/{order_id}

Modify action in Omni prefill orders

Omni AI structured “prefill order” cards can now suggest a modify action (PrefillModifyOrderAction) in addition to the existing new-order and cancel-order actions, letting the assistant propose an amendment to a working order.

  • GET /v1/omni-ai/messages/{message_id}
  • GET /v1/omni-ai/threads/{thread_id}/messages

INDEX security type

INDEX is now a valid value in the security-type enum. It appears on instrument responses and is accepted by the instrument_type filter when listing or cancelling orders.

  • GET /v1/instruments
  • GET /v1/accounts/{account_id}/orders
  • DELETE /v1/accounts/{account_id}/orders

Order and fill instrument fields are now nullable

On order and execution (fill) responses, instrument_id, symbol, and (for orders) instrument_type are now nullable and no longer guaranteed present. They are null when an order or fill has no single resolvable instrument. Code that assumes these fields are always populated should add a null check.

  • GET /v1/accounts/{account_id}/orders
  • GET /v1/accounts/{account_id}/orders/{order_id}

Omni entitlements: trading_account_id renamed to account_id

On the Omni AI entitlements endpoint, the trading_account_id query parameter and the matching trading_account_id response field have both been renamed to account_id. Update any requests or response parsing that used the old name.

  • GET /v1/omni-ai/entitlements

Annual financials and earnings report timing

Two additions to instrument data:

  • The fiscal-period enum on fundamentals and financial-statement responses now includes ANNUAL (alongside the existing quarterly periods).
  • Earnings entries in instrument events now carry a nullable report_time field with values BMO (before market open) and AMC (after market close).
  • GET /v1/instruments/{instrument_id}/fundamentals
  • GET /v1/instruments/events
  • GET /v1/instruments/{instrument_id}/events

Symbols accepted more widely; market-hours date optional

Quality-of-life improvements to filtering:

  • instrument_ids and underlying_instrument_ids now accept instrument symbols (equity tickers or OSI option symbols) in addition to UUIDs on order, instrument-event, and market-data snapshot lookups.
  • The date parameter on the market-hours calendar is now optional and defaults to today.
  • GET /v1/accounts/{account_id}/orders
  • GET /v1/instruments/events
  • GET /v1/market-data/snapshot
  • GET /v1/calendars/market-hours

Tradability flag on option contracts

Option contract responses now include a required is_tradable boolean indicating whether the contract is currently tradable.

  • GET /v1/instruments/options/contracts

Clearer index snapshots

For index instruments, the market-data snapshot’s last-trade now reports the current index level in price with size always 0 (an index level is computed, not traded).

  • GET /v1/market-data/snapshot

Index-aware market data and fundamentals

Better handling for instruments that don’t have certain data by definition (for example, an index):

  • The daily-summary response gains a required not_applicable boolean that distinguishes “this instrument type has no daily summary” from “data not yet loaded.”
  • The fundamentals endpoint now returns a 400 for instruments whose type has no fundamentals.
  • GET /v1/market-data/daily-summary
  • GET /v1/instruments/{instrument_id}/fundamentals

position_effect removed from order submission

The position_effect request field (with its OPEN / CLOSE enum), previously required on options orders, has been removed from order submission. Remove it from your order payloads.

  • POST /v1/accounts/{account_id}/orders

Executions filter renamed to instrument_ids

On the executions endpoint, the instrument_id query parameter has been renamed to instrument_ids and now accepts a comma-separated list of instrument IDs or symbols, returning executions matching any of them.

  • GET /v1/accounts/{account_id}/executions

Screener field_filter and option position types removed

Two enum/field removals:

  • The deprecated field_filter property has been removed from the screener request and response schemas. Use columns for field selection instead.
  • The option-specific position types LONG_CALL, SHORT_CALL, LONG_PUT, and SHORT_PUT have been removed from the position type enum. Positions now report only LONG or SHORT.
  • POST /v1/screener
  • POST /v1/saved-screeners
  • GET /v1/saved-screeners
  • GET /v1/saved-screeners/{screener_id}
  • PUT /v1/saved-screeners/{screener_id}
  • GET /v1/accounts/{account_id}/positions

One-sided quotes in snapshots

The snapshot quote fields bid, ask, and midpoint are no longer required and may be null — for example, on a one-sided quote where only a bid or only an ask is present.

  • GET /v1/market-data/snapshot

Idle Omni threads return 200 instead of 404

Requesting the latest response for an idle thread now returns 200 with data: null rather than 404. A 404 from this endpoint now unambiguously means the thread was not found. If you previously treated 404 as “thread is idle,” switch to checking for a null data.

  • GET /v1/omni-ai/threads/{thread_id}/response

Filter accounts by id and name

Listing accounts now supports two optional query filters:

  • account_id — lexicographic prefix match on the decimal account id (e.g. 100 matches 100345 and 100567).
  • account_name — case-insensitive substring match on the account’s full name.

When both are supplied, an account must match both.

  • GET /v1/accounts

Filter orders by order_ids

The order-list endpoint accepts a new order_ids query parameter — a comma-separated set of order IDs — to fetch a specific group of orders in one call.

  • GET /v1/accounts/{account_id}/orders

Instrument expiry/strike_price and screener field_filter

Advance notice of fields being retired:

  • Instrument expiry and strike_price are deprecated and now always return null — read contract details from the options endpoints instead.
  • The screener field_filter request field is deprecated in favor of columns.
  • GET /v1/instruments
  • GET /v1/instruments/{instrument_id}
  • GET /v1/instruments/search
  • POST /v1/screener

Look up instruments by symbol

The instrument_ids filter on the instruments endpoint now accepts symbols (an equity symbol or an OSI option symbol) in addition to instrument UUIDs. Symbols are resolved server-side, so you no longer need a UUID round-trip to filter by ticker.

  • GET /v1/instruments

Screener

The Trading API now exposes a Screener for querying instruments against fundamental and reference criteria, plus the ability to save and reuse screens.

POST /v1/screener runs a structured screen and returns a columnar row/column result. Requests describe the fields to return (columns), filters (with a rich operator set), sorting, and pagination.

Persist a screen and manage it over time:

  • GET /v1/saved-screeners — list your saved screeners
  • POST /v1/saved-screeners — create one
  • GET /v1/saved-screeners/{screener_id} — fetch one
  • PUT /v1/saved-screeners/{screener_id} — replace one
  • DELETE /v1/saved-screeners/{screener_id} — delete one
  • POST /v1/screener
  • GET /v1/saved-screeners
  • POST /v1/saved-screeners
  • GET /v1/saved-screeners/{screener_id}
  • PUT /v1/saved-screeners/{screener_id}
  • DELETE /v1/saved-screeners/{screener_id}

Live P&L on balances and positions

New profit-and-loss fields, computed in real time:

  • Balances gains three required fields: unrealized_pnl (total unrealized P&L across open positions), daily_pnl (total P&L since start of day), and daily_change (current equity vs. start-of-day equity).
  • Each position gains an optional daily_realized_pnl, and the positions sort_by parameter accepts a new DAILY_REALIZED_PNL value.
  • GET /v1/accounts/{account_id}/balances
  • GET /v1/accounts/{account_id}/positions

ENGINE_REJECTED status removed

The ENGINE_REJECTED value has been removed from the position-instruction status enum. Instructions that fail pre-venue validation now report status: REJECTED with a rejection_reason. Note that instructions failing pre-acceptance validation (duplicate instruction_id, DNE/CEA on a non-expiry day, insufficient position, or an unresolvable instrument) are never persisted — they appear only in the submission response, not in the instructions list.

  • POST /v1/accounts/{account_id}/positions/instructions
  • GET /v1/accounts/{account_id}/positions/instructions

Per-session buying power on balances

The margin section of the balances response gains two required objects, intraday_details and overnight_details, each exposing that session’s buying_power and an optional margin multiplier.

  • GET /v1/accounts/{account_id}/balances

Day-trade fields on balances deprecated

Several day-trade fields on the balances response are deprecated and will be removed in a future release:

  • The start-of-day day_trade_buying_power, day_trade_buying_power_usage, day_trade_count, and pattern_day_trader fields.
  • The day_trade_buying_power_usage field on each margin top-contributor entry.
  • GET /v1/accounts/{account_id}/balances

Smarter option search

Instrument search now matches option contracts by OSI prefix — a root plus a YYMMDD expiry (e.g. AAPL 261217) — and by root-scoped phrases such as AAPL Dec 250 call, in addition to full OSI symbols.

  • GET /v1/instruments/search

Richer batch errors, typed deletes, multi-underlier filter

A set of refinements:

  • On position-instruction submissions where every row is rejected, the 400 / 409 / 503 responses now return the full per-row data list (each row carrying its status and rejection_reason) instead of a bare error, and a new 500 response covers an all-rows-rejected internal fault.
  • Delete endpoints now return a typed body (data: null) instead of an untyped empty response.
  • The underlying_instrument_ids order filter now accepts multiple underlier instrument IDs (array) rather than a single value.
  • POST /v1/accounts/{account_id}/positions/instructions
  • DELETE /v1/watchlists/{watchlist_id}
  • DELETE /v1/watchlists/{watchlist_id}/items/{item_id}
  • GET /v1/accounts/{account_id}/orders

Instrument restriction flag and security types removed

Removals to instrument data:

  • The is_restricted field has been removed from instrument and option-contract responses, along with the is_restricted filter on the instruments endpoint and the include_restricted parameter on instrument search.
  • PREFERRED_STOCK and OTHER have been removed from the security-type enum, which is now COMMON_STOCK, OPTION, CASH. This affects the instrument_type order filter and the security-type field on instrument responses.
  • GET /v1/instruments
  • GET /v1/instruments/{instrument_id}
  • GET /v1/instruments/search
  • GET /v1/instruments/options/contracts
  • GET /v1/accounts/{account_id}/orders

Option greeks in snapshots

Market-data snapshots for option instruments now include a greeks object with theo_price, iv, delta, gamma, vega, theta, rho, and a timestamp (per-share values). It is null for equities.

  • GET /v1/market-data/snapshot

Publicly-traded-partnership flag

Instruments now carry a required is_ptp boolean flagging publicly-traded partnerships (PTP sales are subject to 10% withholding for non-US tax residents). Related filters were added too:

  • is_ptp boolean filter on the instruments endpoint.
  • include_ptp on instrument search (default true; PTP instruments are penalized in ranking when included).
  • GET /v1/instruments
  • GET /v1/instruments/{instrument_id}
  • GET /v1/instruments/search
  • GET /v1/instruments/options/contracts

Executions endpoint

A new endpoint returns individual execution reports for an account. Each execution includes id, order_id, symbol, instrument_id, side, quantity, price, and transaction_time, ordered by transaction time (newest first), with instrument_id, from, to, and pagination filters.

  • GET /v1/accounts/{account_id}/executions

Latest Omni messages first

Fetching thread messages now returns the latest page of finalized messages by default (chronological within each page) instead of starting from the earliest message.

  • GET /v1/omni-ai/threads/{thread_id}/messages

Omni AI response format changes

Three changes that affect clients parsing Omni AI content:

  • Ticker references inside message text changed from XML-style tags (<ticker>AAPL</ticker>) to markdown links ([AAPL](ticker:AAPL)).
  • Entitlement request fields were renamed: trading_account_ids → account_ids and requested_entitlement_codes → entitlement_codes.
  • The symbolChart chart-card option and its SymbolChart schema were removed; chart cards now use the series-driven dataChart only.
  • GET /v1/omni-ai/threads/{thread_id}/messages
  • GET /v1/omni-ai/threads/{thread_id}/response
  • POST /v1/omni-ai/entitlements

Fractionable instrument flag

Instruments now include a required is_fractionable boolean indicating whether the instrument supports fractional-quantity orders.

  • GET /v1/instruments
  • GET /v1/instruments/{instrument_id}
  • GET /v1/instruments/search
  • GET /v1/instruments/options/contracts

Instrument type inferred on order submission

The instrument_type request field is no longer required on order submission — the security type is now inferred from the instrument you reference.

  • POST /v1/accounts/{account_id}/orders

Last-trade size in snapshots

The last_trade object in market-data snapshots gains a required size field — the share quantity of the most recent last-sale-eligible trade.

  • GET /v1/market-data/snapshot

Documented position-instruction lifecycle

The full lifecycle-status model for position instructions is now documented: SENT, ACCEPTED, REJECTED, CANCEL_REQUESTED, CANCELLED, CANCEL_FAILED, and UNKNOWN, along with typical rejection causes (duplicate instruction_id, DNE/CEA on a non-expiry day, insufficient position, unresolved instrument).

  • POST /v1/accounts/{account_id}/positions/instructions
  • GET /v1/accounts/{account_id}/positions/instructions

Batch position instructions and reporting currency

Two additions:

  • Batch submission semantics for position instructions are now defined: all rows accepted returns 200; partial success returns 207 (Multi-Status) with rejected rows carrying a rejection_reason; and all-rejected returns a 4xx/5xx (409 duplicate instruction_id, 400 validation failures, 503 clearing unavailable).
  • A nullable reporting_currency field was added to instrument events, analyst-reporting, and fundamentals responses.
  • POST /v1/accounts/{account_id}/positions/instructions
  • GET /v1/instruments/events
  • GET /v1/instruments/{instrument_id}/analyst-reporting
  • GET /v1/instruments/{instrument_id}/fundamentals

Top-level error removed from position instructions

The separate top-level error field has been removed from the position-instruction response object. Per-row rejection detail is now carried in each row’s rejection_reason.

  • POST /v1/accounts/{account_id}/positions/instructions
  • GET /v1/accounts/{account_id}/positions/instructions

Partial portfolio-history results

Portfolio history can now return a 207 (partial success) when one side of the fetch fails, delivering the available segments alongside a top-level error describing the portion that failed.

  • GET /v1/accounts/{account_id}/portfolio-history

Bidirectional pagination

page_token now supports paging backward as well as forward: a token can retrieve the next or the previous page of results. This applies to all paginated list endpoints (orders, executions, positions, instruments, events, news, Omni threads and messages, watchlists, and more). No request changes are required.

  • GET /v1/accounts/{account_id}/orders
  • GET /v1/instruments
  • GET /v1/news
  • GET /v1/omni-ai/threads/{thread_id}/messages

Initial release

First release of the Clear Street Trading API — a unified REST API covering order management, positions, market data, and account services.

  • Accounts — list and fetch accounts, update account settings, and read balances and portfolio history.
  • Orders — submit, list, fetch, replace, and cancel orders. Sides BUY, SELL, and SELL_SHORT; order types MARKET, LIMIT, STOP, and STOP_LIMIT; with support for trailing stops and extended-hours sessions.
  • Positions — list positions, close positions, and manage position instructions.
  • Instruments — look up and search instruments, list option contracts, and read corporate-action events.
  • Instrument data — fundamentals, income statements, balance sheets, cash-flow statements, analyst reporting, and news.
  • Market data — real-time snapshots and daily summaries.
  • Calendar — market clock and market-hours calendar.
  • Watchlists — create and manage watchlists and their items.
  • Omni AI — threads, messages, responses, feedback, and entitlements for Clear Street’s financial AI assistant.

See Get Started to make your first call.