tastytradeDeveloper Docs
Legacy ↗

Agent Quickstart

This is a single, self-contained walkthrough an AI agent can follow to complete a full trade in sandbox: discover the API, mint a token, fetch a quote, dry-run an order, submit it safely, and confirm the fill. Stay in sandbox (https://api.cert.tastyworks.com) until the whole flow is verified; production (https://api.tastyworks.com) is real money and requires explicit human approval.

Consider the MCP server for autonomous flows. The tastytrade MCP server is self-hosted and open source; its five order-submitting tools are gated behind a dry-run-first confirmation token, with sanity checks and rate limits on top. Note its default endpoint is production. This page shows the raw HTTP golden path so you understand what the MCP server does for you.

Two rules apply to every request below: send Authorization: Bearer <token> and send a User-Agent header in the form <product>/<version> (e.g. my-agent/1.0). Requests without a User-Agent are rejected. Never log, echo, or commit tokens.

1. Discover the API

Fetch /llms.txt — the machine-readable index that points to every doc and reference page. Use it to locate endpoints instead of guessing. It is served by this documentation site (the same origin as this page), not by the trading API host.

# Use this documentation site's origin — not api.cert.tastyworks.com
curl 'https://<docs-site-host>/llms.txt' -H 'User-Agent: my-agent/1.0'

2. Mint a 15-minute access token

Exchange your refresh token for a short-lived access token. It is valid for 15 minutes and cannot be extended — mint a fresh one when it expires. See Get started for obtaining credentials.

curl -X POST 'https://api.cert.tastyworks.com/oauth/token' \
  -H 'User-Agent: my-agent/1.0' \
  -H 'Content-Type: application/json' \
  -d '{
    "grant_type": "refresh_token",
    "refresh_token": "YOUR_REFRESH_TOKEN",
    "client_id": "YOUR_CLIENT_ID",
    "client_secret": "YOUR_CLIENT_SECRET"
  }'

The response contains access_token. Then resolve your account number from GET /customers/me/accounts.

3. Fetch a quote

Pull real-time market data over REST for up to 100 symbols at once. Use tastytrade symbology: equities (AAPL), OCC equity options, futures (/-prefixed), future options (./-prefixed), and crypto pairs (BTC/USD).

GET /market-data/by-type?equity=AAPL
Authorization: Bearer YOUR_ACCESS_TOKEN
User-Agent: my-agent/1.0

For live streaming, obtain an API quote token (GET /api-quote-tokens, 24h expiry) and connect to the DXLink WebSocket using the COMPACT format. See Streaming.

4. Dry-run the order first

Orders are money-moving — always dry-run first. Post the order body to the dry-run endpoint and confirm it returns no errors; inspect buying-power-effect and fee-calculation before going live.

POST /accounts/{account_number}/orders/dry-run
Authorization: Bearer YOUR_ACCESS_TOKEN
User-Agent: my-agent/1.0
Content-Type: application/json
{
  "time-in-force": "Day",
  "order-type": "Limit",
  "price": "1.00",
  "price-effect": "Debit",
  "legs": [
    {
      "instrument-type": "Equity",
      "symbol": "AAPL",
      "quantity": 1,
      "action": "Buy to Open"
    }
  ]
}

Note the dasherized JSON keys (order-type, price-effect). A failed validation returns a 422 with an error.code you can branch on.

5. Submit with a unique external-identifier

Once the dry-run is clean, submit to the live endpoint and include a unique external-identifier field in the order body. tastytrade has no idempotency-key header and does not deduplicate retried submissions, so this id is how you recognize your order on a retry.

POST /accounts/{account_number}/orders
Authorization: Bearer YOUR_ACCESS_TOKEN
User-Agent: my-agent/1.0
Content-Type: application/json
{
  "time-in-force": "Day",
  "order-type": "Limit",
  "price": "1.00",
  "price-effect": "Debit",
  "external-identifier": "my-agent-2026-06-09-aapl-001",
  "legs": [
    {
      "instrument-type": "Equity",
      "symbol": "AAPL",
      "quantity": 1,
      "action": "Buy to Open"
    }
  ]
}

The external-identifier you send is echoed back on the order object. (Order responses and account-streamer messages also carry a system-populated, read-only ext-client-order-id — never try to set or send that field yourself.)

If the submit response is uncertain (timeout or 5xx), do not blindly resubmit — the server will not deduplicate. List your orders first (GET /accounts/{account_number}/orders, or /accounts/{account_number}/orders/live) and check whether one carrying your external-identifier already exists. See Idempotency & retries.

6. Confirm the fill

A successful submit returns an order with status Routed. Poll the order (or stream order updates) until it reaches a terminal status. The lifecycle flows roughly: ReceivedRoutedIn FlightLiveFilled.

StatusTerminalMeaning
LiveNoWorking at the exchange
FilledYesOrder fully filled — a position and transaction are created
CancelledYesOrder was cancelled
RejectedYesRejected by tastytrade or the exchange
ExpiredYesDay order that did not fill before close

Once Filled, confirm by fetching the account's balances and positions. tastytrade may mark an order Filled before every leg's fills finish processing — if a leg looks short, re-fetch after a brief delay.

Safety checklist

  • Sandbox until verified; get explicit human approval before production.
  • Dry-run first, then submit with a unique external-identifier.
  • On 429, back off exponentially and retry — see Rate limits & backoff.
  • Branch on the error code, not message text — see Error reference.

Next steps