Orders & Order Types
An order in the tastytrade API is a JSON document with two parts: order attributes that apply to the trade as a whole, and a legs array where each leg names a single instrument, a side, and a quantity. All JSON keys are dasherized (for example order-type, price-effect, time-in-force, instrument-type), and prices/values are sent as strings or decimals.
Orders are submitted to POST /accounts/{account_number}/orders. Because orders move real money, always dry-run first against POST /accounts/{account_number}/orders/dry-run (the same JSON body), inspect the returned buying-power-effect/fee-calculation and any warnings, then submit. There is no idempotency-key header and the API does not deduplicate retried submissions, so set your own unique external-identifier on each order (it is echoed back on the order response); if a submission's outcome is uncertain (timeout or 5xx), check GET /accounts/{account_number}/orders with a start-date on or before the day you submitted, in US Eastern time (for example, the previous day), or /orders/live, for that identifier before resubmitting. See Idempotency & retries and the full schema at /reference/orders.
Order attributes
| Attribute | Required | Meaning |
|---|---|---|
order-type | Yes | The kind of order (see below) |
time-in-force | Yes | How long the order lives if unfilled |
price | Yes for Limit / Stop Limit | The limit price |
price-effect | With price | Debit (you pay) or Credit (you receive) |
stop-trigger | Yes for Stop / Stop Limit | The trigger price |
gtc-date | Yes for GTD | Expiry date (yyyy-mm-dd) |
value / value-effect | Yes for Notional Market | Dollar amount to buy/sell |
legs | Yes | Array of leg objects |
source | No | Free-form origin tag |
price-effect must agree with the leg action: buying is a Debit, selling is a Credit. Buying for a credit (or selling for a debit) is rejected.
Legs
Each leg names one instrument. All orders need at least one leg. Equity, future, and cryptocurrency orders are limited to 1 leg; equity-option and future-option orders allow up to 4 legs. Two legs may not share the same symbol.
| Leg attribute | Required | Meaning |
|---|---|---|
action | Yes | Buy to Open, Sell to Open, Buy to Close, Sell to Close (or Buy/Sell for single-leg outright futures) |
instrument-type | Yes | Equity, Equity Option, Future, Future Option, or Cryptocurrency |
quantity | Yes (omit for Notional Market) | Whole number, or decimal for crypto |
symbol | Yes | The instrument symbol |
The action and instrument-type values above are the commonly used ones — the full enums (which also include Allocate, Equity Offering, Fixed Income Security, and Liquidity Pool) are in /reference/orders.
Symbols follow tastytrade symbology: plain tickers for equities (AAPL), OCC-style strings for equity options (AAPL 230818C00197500), leading-slash futures (/CLZ2), future options, and crypto pairs (BTC/USD). Look symbols up via the instruments endpoints — see /reference.
Order types
| Type | Rule |
|---|---|
Limit | Must include price and price-effect |
Market | No price/price-effect; single leg; time-in-force not GTC (for cryptocurrency orders the time-in-force rules are the crypto rules instead; the other Market rules still apply) |
Stop | Market order with a stop-trigger; becomes a market order when the quote hits the trigger |
Stop Limit | Limit order (price + price-effect) plus a stop-trigger |
A Notional Market type also exists for buying a dollar value of crypto or eligible equities (omit quantity). These are the commonly used order types — the full order-type enum (which also includes Marketable Limit and Liquidity Allocation) is in /reference/orders.
{
"time-in-force": "Day",
"order-type": "Limit",
"price": "1.09",
"price-effect": "Debit",
"legs": [
{ "instrument-type": "Equity Option", "symbol": "AAPL 230818C00197500", "quantity": 1, "action": "Buy to Open" },
{ "instrument-type": "Equity Option", "symbol": "AAPL 230818C00200000", "quantity": 1, "action": "Sell to Open" }
]
}
Time-in-force
| TIF | Meaning |
|---|---|
Day | Works until filled or the market closes |
GTC | Good 'til canceled — works until filled or canceled |
GTD | Good 'til date — also requires gtc-date (yyyy-mm-dd) |
Some venues also support immediate-or-cancel and extended-hours behaviors; refer to /reference/orders for the values your instrument accepts.
Cryptocurrency orders
Cryptocurrency trading is currently disabled through the API. The release notes record that it was disabled as of release
20260629, until further notice. The rest of this section describes the order shape for when it is enabled; do not build against it before the release notes say it is back.
The is-cryptocurrency-enabled and is-cryptocurrency-closing-only fields returned by GET /accounts/{account_number}/trading-status are per-account flags for whether an account may trade cryptocurrency. They do not say whether the API currently accepts crypto orders.
Cryptocurrency orders use the same POST /accounts/{account_number}/orders endpoint and body as any other order, with instrument-type set to Cryptocurrency and a pair symbol such as BTC/USD.
Finding supported products. GET /instruments/cryptocurrencies returns the active crypto instruments (filter with symbol[]=BTC%2FUSD; URL-encode the /). Use each instrument's symbol field as the leg symbol. An instrument with is-closing-only set to true accepts only closing orders.
Quantity and price precision.
- Quantity may be a decimal for crypto.
GET /instruments/quantity-decimal-precisionsreturns, per instrument type or symbol, avaluegiving the number of decimal places a quantity may use (0means whole numbers only). In the reference example BTC/USD has avalueof8, so0.12345678is valid and0.123456789is not. - Price: an opening order's
pricemust follow the instrument'stick-size. A closing order'spricemay use any number of decimal places up to the highestmax-price-precisionamong the instrument'sdestination-venue-symbolsentries that haveroutableset totrue. See the instruments reference and the rules below.
Order shape. A crypto order has a single leg. Send a decimal quantity as described above, or use a Notional Market order that buys a dollar value and omits quantity. A Notional Market example:
{
"time-in-force": "IOC",
"order-type": "Notional Market",
"value": "10.0",
"value-effect": "Debit",
"legs": [
{ "instrument-type": "Cryptocurrency", "symbol": "BTC/USD", "action": "Buy to Open" }
]
}
Order rules and limits. The order service's own checks on a cryptocurrency order are listed below. They apply when crypto trading is available to your account and client, and say nothing about whether that is the case today; the notice at the top of this section does. The order types and time-in-force values listed are the ones the order service's code accepts. They are not a guarantee that a given combination is accepted on submission; see the venue rules note after the table.
| Rule | What the order service enforces | Rejection code |
|---|---|---|
| Legs | Exactly one leg | cryptocurrency_single_leg_only |
| Action | Buy to Open or Sell to Close. Buy to Close is accepted only for orders the service treats as forced. | cryptocurrency_invalid_action |
| Order type | Limit, Market, or Notional Market | cryptocurrency_invalid_type |
| Time in force | IOC or GTC; any other value is rejected. A Notional Market order must be IOC. | tif.cryptocurrency_invalid, cryptocurrency_notional_market_orders_ioc_only |
gtc-date | Must not be set | cryptocurrency_no_gtc_date |
| Maximum quantity | 2,147,483,647 per leg | order_limit_check_failed |
| Minimum notional value | $1 for an order with an opening leg; $0.01 for a closing order. The rejection message formats the minimum with no decimals, so for a closing order it reads "$0". | below_notional_value_minimum |
| Maximum notional value | $75,000 | above_notional_value_maximum |
| Opening price | Must follow the instrument's tick-size (checked when the order has a price) | invalid_price_increment |
| Closing price | At most the highest routable max-price-precision decimal places (checked when the order has a price). If the instrument has no routable destination-venue-symbols, the limit is the number of decimal places in its tick-size. | cryptocurrency_invalid_closing_price |
| Price band, buy | A Limit buy price may be at most 1.20 times the current ask | cryptocurrency_unreasonable_price_max |
| Price band, sell | A Limit sell price may be at most 1.55 times the current ask | cryptocurrency_unreasonable_price_max |
| Price band, minimum | A Limit price may not be below 0.25 times the current bid | cryptocurrency_unreasonable_price_min |
The notional-value limits are checked on the order's notional value as the order service calculates it, for every crypto order type and not only Notional Market. The quantity limit is a fixed ceiling, not a statement of what the instrument accepts; the quantity precision rules above still apply. The quantity limit, the notional limits and the price-band multipliers are fixed values in the order service's code, not account settings. The message for order_limit_check_failed is in the preflight error list; it suggests contacting the trade desk to increase your limits, but the crypto quantity limit is this fixed value, so that advice does not apply to it.
Venue rules and dry-run. The table lists the order service's own checks. On submission the service also matches the order against routing-venue rules that are stored in a database. Those rules can further restrict order type and time in force (each type and each time in force is a separate on/off setting, for example Market, Notional Market, IOC and GTC). The same venue selection also checks that the symbol is routable and checks quantity and price precision. If no venue accepts the order, it is rejected with cryptocurrency_venue_not_found. If a venue matches but no compatible order router is left for it, the rejection is no_router_found ("No compatible order router found."). A dry-run does not run this step, so a dry-run that passes does not guarantee that the order will be accepted on submission. The venue rules are not published, so this page does not say which type and time-in-force combinations are enabled; in particular it does not say whether a Market order with GTC is accepted, even though no crypto check in the table rejects it.
Blocked for API clients. The order service can block an instrument type for API clients. When it does, an order from an OAuth2 client for that type is rejected with a 422, and the entry in error.errors[] is:
{
"code": "api_forbidden_type",
"message": "Order contains instrument types that are not currently allowed for API trading: <instrument types>"
}
Orders sent without an OAuth2 client are not checked, and clients the service has allowlisted are exempt. Which types are blocked, and which clients are allowlisted, is service configuration that is not published, so this page does not say whether api_forbidden_type is how crypto is disabled today. The same check can reject specific symbols with the code api_forbidden_symbol.
Preflight stops at the first stage that reports an error. The crypto gatekeeper stage runs before the blocked-type check, so an order it rejects with cryptocurrency_trading_not_supported ("Cryptocurrency trading is not supported.") or cryptocurrency_not_allowed ("Your account is not approved for cryptocurrency trading. Please enable it to trade this product.") never reaches it. The blocked-type check in turn runs before the order-shape and limit checks in the table, so a blocked order is rejected with api_forbidden_type even if it also breaks one of those rules.
A failed pre-submission check comes back as a 422 with a preflight_check_failure code (see Errors); each failure is an entry in error.errors[] with its own code.
Complex orders
Complex (bracket) orders are submitted to POST /accounts/{account_number}/complex-orders and have a type plus an orders array (and, for triggered types, a trigger-order; PAIRS adds ratio-price fields — see below). Supported types are OTOCO, OCO, OTO, and PAIRS. BLAST is deprecated and is not supported in any environment.
- OTO — the
trigger-ordergoes live immediately; when it fills, itsorders(up to 3) are routed. They do not cancel one another. - OCO — no
trigger-order; theordersgo live immediately, and when one fills the other is canceled. - OTOCO — a
trigger-orderplus one to three OCO pairs (2, 4 or 6orders) that sit inContingentstatus until the trigger fills, then route as OCOs. - PAIRS —
ordersworked together as a pairs strategy, triggered by a ratio price: setratio-price-comparator(gteorlte) andratio-price-threshold(a decimal serialized as a JSON string, e.g."150.25"); optionally setratio-price-is-threshold-based-on-notionalto compare on notional value instead of price. A working PAIRS order's threshold and comparator can later be edited viaPATCH /accounts/{account_number}/complex-orders/{id}(only PAIRS orders can be edited there).
{
"type": "OTOCO",
"trigger-order": {
"order-type": "Limit", "price": 157.97, "price-effect": "Debit", "time-in-force": "Day",
"legs": [{ "instrument-type": "Equity", "symbol": "AAPL", "action": "Buy to Open", "quantity": 100 }]
},
"orders": [
{ "order-type": "Limit", "price": 198.68, "price-effect": "Credit", "time-in-force": "GTC",
"legs": [{ "symbol": "AAPL", "instrument-type": "Equity", "action": "Sell to Close", "quantity": 100 }] },
{ "order-type": "Stop", "time-in-force": "GTC", "stop-trigger": 143.06,
"legs": [{ "symbol": "AAPL", "instrument-type": "Equity", "action": "Sell to Close", "quantity": 100 }] }
]
}
The response returns a complex-order.id (used to fetch or cancel the whole bracket) plus individual ids for the trigger and nested orders. Cancel a complex order through its own endpoint using the complex-order id, not a nested order id.
Price restrictions on triggered orders
An OTOCO order is checked to make sure its orders are priced sensibly relative to the trigger-order: in each OCO pair, the profit-taking order has to sit on the profitable side of the trigger order's price, and the stop-loss order on the other side. This check runs for OTOCO only; it is not applied to OTO, OCO, or PAIRS orders. It applies to every order in orders, except that an order in orders that has already reached a terminal status is skipped.
Each order in orders is compared against a reference price, strictly (equal prices are rejected). Credit or debit is taken from the order's price-effect; if it has none (as with the Stop in the example above, which has no price), from its value-effect, and for a single-leg order after that from the leg action (a buy is a debit, a sell is a credit):
Order in orders (credit or debit) | Price that is compared | Must be |
|---|---|---|
Credit, Limit | price | greater than the reference price |
Credit, Stop | stop-trigger | less than the reference price |
Credit, Stop Limit | price (the limit price, not stop-trigger) | less than the reference price |
Debit, Limit | price | less than the reference price |
Debit, Stop | stop-trigger | greater than the reference price |
Debit, Stop Limit | price (the limit price, not stop-trigger) | greater than the reference price |
In other words, for a long trigger order the profit order must be priced above the trigger price and the stop-loss below it; for a short trigger order the profit order must be priced below and the stop-loss above. A Market order cannot be used in orders: it has no price to compare, so it fails this check.
The reference price is the trigger order's price for a Limit or Stop Limit trigger order, or its stop-trigger for a Stop trigger order. If the trigger order has no price (a Market order), or if it has already filled, the current mid price of the trigger order's legs is used instead (the last trade price for any leg that has no mid). If a leg has neither, the reference price falls back to 0.01, so an OTOCO with a Market trigger order is rejected when no quote is available for it.
The example above passes: the trigger order buys at 157.97, the profit Limit credit is at 198.68 (above it), and the Stop credit triggers at 143.06 (below it).
An order that breaks these rules is rejected with the preflight error code invalid_triggered_order_price and the message Order price is invalid for this trade.
The same check runs when you replace an order that belongs to an OTOCO with PUT or PATCH on /accounts/{account_number}/orders/{id}. A new trigger order is checked against the existing orders; a new order in orders is checked against the trigger order's price, or against the current mid price once the trigger order has filled.
Related
- /reference/orders — full order request/response schema
- /reference/errors —
400/401/403/404/422/429/5xxhandling (a failed preflight check returns422) - Idempotency & retries and Rate limits & backoff
- Get started and the MCP server