Broker API Capability Discovery
Direct Answer
Broker API documentation describes what a vendor intends their API to support. It does not reliably describe what the API actually does for your specific use case, your account type, your asset class, your order size, your jurisdiction. Capability discovery is the practice of systematically probing the API to build a ground-truth record of what it actually accepts, what it silently modifies, and what it rejects with actionable errors versus ambiguous ones.
The output of capability discovery is a capability manifest: a structured document or code object that records which order types work, which TIF combinations are valid per order type, which asset classes are accessible, what the minimum and maximum order sizes are, whether fractional shares are supported, and what the actual rate limits are, not what the documentation says they are. This manifest drives adapter logic and prevents your system from attempting operations it discovers at runtime are unsupported.
Key Takeaways
- Documentation lies by omission: Most broker docs describe the common path. Edge cases, what happens when you submit a GTC limit on an options contract, or a market order on a halted stock, are discovered only through testing.
- Capability varies by account type: A cash account, margin account, and options account at the same broker may support different order types and different behaviors for the same order type. Discover capabilities for your specific account type.
- Test in the sandbox with a capability matrix: Create a structured test matrix: for every order type × TIF combination you need, submit a small test order in sandbox and record the outcome. Accepted, rejected with which error, or silently modified?
- Probe rate limits empirically: Send requests at increasing rates until you receive a 429, then measure the retry-after period. Documented limits are often different from enforced limits, and the enforcement can vary by endpoint.
- Record undocumented constraints: Minimum lot sizes, tick size requirements, maximum order values, and symbol-level restrictions are often enforced without documentation. Record every rejection you encounter, including the error code and message.
- Re-run discovery after broker updates: Broker APIs change. A capability that worked last month may be deprecated or modified. Schedule periodic capability re-validation against the sandbox as part of your integration testing routine.
- Watch for silent coercion: Some brokers accept requests that violate their rules but coerce the values silently, converting a limit order to a market order, rounding a quantity, or changing TIF from GTC to DAY. The response code is 200 but the order is not what you submitted.
- Document not just what works but what fails: A capability manifest that only lists supported features leaves your adapter guessing about unsupported ones. Record known-unsupported capabilities explicitly with the error code and message they produce.
Core Concepts
Building the Test Matrix
The capability test matrix is a two-dimensional grid: one axis lists every order type your strategy needs (market, limit, stop, stop_limit, trailing_stop), and the other axis lists every TIF value (day, gtc, ioc, fok, gtd, opg, cls). Each cell in the matrix gets populated through a sandbox test: submit a 1-share or minimum-lot order with those parameters against a liquid instrument and record the broker's response.
Response categories to track per cell: accepted (200, order created), accepted-with-modification (200, but the returned order differs from what you submitted, check every field), rejected-with-specific-error (4xx with a structured error code and message), rejected-with-generic-error (4xx with an unstructured or opaque message), and timeout (no response within your deadline). The modification case is the most dangerous because it silently changes your order.
Run the matrix against at least two instruments: a highly liquid equity (AAPL, SPY) and a lower-liquidity or restricted instrument that is more likely to expose order type restrictions. Some brokers apply different rules to OTC stocks, ETFs, and options even when they don't document the distinction.
Automate the matrix. Write a test script that iterates all combinations, submits orders with a distinctive client-order-ID prefix (e.g., CAPTEST-{uuid}), records the response, and immediately cancels any that were accepted. The script output becomes your initial capability manifest.
Probing Rate Limits
Published rate limits and enforced rate limits frequently diverge. A broker may document "200 requests per minute" but enforce a burst limit of 10 requests per second, meaning 200/min is the sustained limit but 11 requests in 1 second triggers a 429 even if you've only made 30 requests in the current minute. You need to discover both the sustained limit and the burst limit.
To probe rate limits: write a script that sends requests at a controlled rate, start at 5/minute, increase by 5/minute each iteration until you receive a 429. When you hit a 429, record the rate you were at, the Retry-After header value (if present), and the exact error response. Then do the same test as a burst: send 5 requests with no delay between them, then 10, then 20, until you hit the burst limit.
Rate limits are often per-endpoint, not global. The order submission endpoint may have a different limit than the market data endpoint or the account status endpoint. Test each endpoint category independently. Interactive Brokers, for example, applies different limits to order-related messages and data requests under its TWS API gateway.
Record rate limit findings as configuration in your adapter middleware: sustained rate (requests per minute), burst rate (requests per second), retry-after behavior (fixed vs. Retry-After header), and whether the limit is per-IP, per-account, or per-API-key. Use these numbers to configure token-bucket rate limiting in your adapter rather than relying on documentation values.
Discovering Account-Level Constraints
Account type dramatically affects what orders are accepted. A cash account at most US brokers cannot short sell and cannot submit market orders near the close in thin stocks. A margin account enables shorting but subjects orders to margin maintenance checks that can cause rejection at unexpected times. An options account has its own order type vocabulary (buy-to-open, sell-to-close, spreads) that requires separate capability discovery.
Request your account details via the account state endpoint early in capability discovery. Record your account type, margin status, options trading level (level 0-4 at most US brokers), and any account restrictions. Some restrictions are communicated as account flags in the API response rather than through documentation.
Cash accounts and margin accounts follow different frequent-trading constraints. A cash account is not subject to a $25,000 Pattern Day Trader equity requirement merely because the customer trades frequently. Cash-account trading instead depends on payment and settlement rules, including whether securities are paid for before they are sold and whether settled funds are available when required. Margin accounts may be subject to a broker's intraday-margin framework. FINRA's new intraday-margin requirements became effective June 4, 2026, and eligible firms may continue using legacy day-trading-margin provisions during a permitted transition period ending no later than October 20, 2027. Always check the broker's current account rules before automating trading behavior. Record whether the broker enforces constraints at the API level via a specific error code or allows submission but flags the account after the fact.
Fractional share support is another account-level variation. Alpaca supports fractional share trading for most US equities in all account types. Interactive Brokers supports fractional shares only for certain account types and only for equities, not options or futures. Test a fractional quantity (e.g., 0.5 shares) submission and record whether the broker accepts it, rounds it, or rejects it.
Symbol-Level and Session-Level Constraints
Many constraints are not global to the account but specific to the instrument or trading session. Extended-hours trading is the clearest example: some brokers support pre-market and after-hours orders only as limit orders, not market orders, and only on their equity accounts, not options. Discover this by submitting a market order during pre-market hours and recording the rejection behavior.
Lot size constraints vary by instrument. US equities typically trade in 1-share lots, but some OTC securities require minimum order sizes of 100 shares. Futures contracts have lot sizes defined by the exchange (1 contract = 1,000 barrels for standard WTI crude oil, 100 troy ounces for standard gold). Crypto exchanges often have base currency minimums (minimum 0.001 BTC, minimum $10 notional). Discover minimums by submitting a 1-unit order and checking whether the broker accepts it or returns a minimum lot size error.
Tick size requirements determine the smallest price increment a limit price can use. US equities generally trade at $0.01 increments, but some thinly traded stocks may require larger increments, and futures contracts have exchange-mandated minimum tick sizes (e.g., $0.01 per barrel for standard WTI crude oil futures). Submit a limit order with a price that violates tick size (e.g., $100.005) and observe whether the broker rounds it, truncates it, or rejects it with an error.
Some instruments have short sale restrictions that change dynamically: SSR (Short Sale Restriction) triggers for US equities that decline more than 10% from the prior day's close. On those days, short sales can only be executed on an uptick. Test whether your broker enforces SSR at the API level or relies on the exchange to enforce it. If the broker enforces it, your adapter needs to handle SSR rejection errors specifically.
Worked Scenario
- Define your needed capabilities. Your strategy needs: market orders with DAY TIF, limit orders with GTC and IOC TIF, and stop-limit orders with DAY TIF. You're trading US equities, you have a margin account, and you need fractional share support.
- Build the test matrix. You write a 15-cell matrix: 3 order types × 5 TIF values (DAY, GTC, IOC, FOK, GTC with a specific date). Your script submits 0.5-share minimum orders of AAPL for each cell in the Alpaca paper environment.
- Run the matrix. Results: market+DAY = accepted. market+GTC = rejected (error: "market orders must use day TIF"). limit+GTC = accepted. limit+IOC = accepted. stop_limit+DAY = accepted. stop_limit+GTC = accepted. Fractional 0.5 AAPL = accepted.
- Probe rate limits. You ramp up from 50/min to 250/min in increments. You hit a 429 at 210/min on the order submission endpoint. The Retry-After header says 15 seconds. You record your adapter config: sustained limit = 200/min, burst = 20/s, retry-after = honor header.
- Record constraints. You discover that the broker's error for market+GTC is code
invalid_request_errorwith message "time_in_force must be 'day' for market orders". You record this in your capability manifest and update the adapter to reject market+GTC at the adapter boundary with a meaningful error before it reaches the wire. - Schedule re-runs. You add a monthly capability re-validation job that re-runs the matrix against the sandbox and diffs the results against the recorded manifest. Any change triggers an alert.
Measurement Framework
| Measurement | Question to Answer |
|---|---|
| Capability matrix coverage (%) | What fraction of required order type × TIF combinations have been empirically tested? |
| Silent-modification rate | How often does the broker return a 200 but with an order that differs from what was submitted? |
| Rate limit headroom (%) | How far below the observed rate limit are you operating at peak? |
| Capability staleness (days since last validation) | When was the capability manifest last re-validated against the current sandbox? |
| Undocumented rejection rate | What fraction of order rejections are for reasons not covered in the broker's public docs? |
Common Failure Modes
Trusting Documentation Over Empirical Testing
The most common failure is building an adapter based purely on reading broker documentation, skipping empirical testing in the sandbox. Documentation is written for the average use case and frequently omits account-type restrictions, symbol-level constraints, and session-specific behavior. A strategy that works in backtesting then fails in live trading because the broker doesn't support a required order type on that account type is a preventable production incident.
Require empirical sandbox testing for every capability claim in your integration. No capability enters the adapter's manifest from documentation alone; it must be confirmed by a successful sandbox test. Document the test date, the sandbox response, and the account type used.
Missing the Burst Limit
A system that passes sandbox testing at moderate request rates then hits 429s in production during high-activity periods has missed the burst rate limit. If your strategy submits orders in batches, for example, when a rebalance signal fires simultaneously across 20 positions, those 20 submissions hit the API within milliseconds of each other, triggering burst protection even if the sustained rate is well within limits.
Discover burst limits explicitly by testing rapid sequential requests, not just sustained rates. Implement request queuing in your adapter that spaces submissions by at least 1/burst_limit seconds when submitting multiple orders.
Silent Coercion Detected Too Late
A broker that accepts a GTC order on an instrument that it internally treats as DAY returns a 200 response. The order appears created. Your system logs a success. Three hours later, the order is filled at a price that looks wrong for a GTC order, because the broker executed it as a DAY order and re-entered at a different price. You only discover the coercion in post-trade reconciliation.
Prevent this by comparing the returned order object from the broker against the submitted order in your adapter. After receiving an order acknowledgment, check that the TIF, order type, quantity, and limit price in the response match what you submitted. Any field mismatch should trigger a warning log and, for TIF or order type changes, an immediate cancel of the mismatched order.
Capability Manifest Not Updated After Broker API Version Change
Brokers version their APIs. When a new API version drops, previously supported order types may be renamed, removed, or require additional fields. A capability manifest that was accurate for API v1 may be wrong for v2. Systems that cache capabilities at startup or in a static config file will operate on stale information after an upgrade.
Treat capability discovery as a recurring process, not a one-time setup step. Re-validate against the sandbox monthly, after any broker announcement about API changes, and when you upgrade the broker's SDK. Automate the comparison: the manifest from the current re-run should be diffed against the previous manifest, with any difference flagged for human review before taking effect in production.
Assuming Symmetric Behavior Across Asset Classes
Many traders assume that because limit+GTC works for US equities it will work the same way for options or ETFs from the same broker. This assumption frequently fails: options may not support GTC, ETFs may have different tick size requirements, and crypto on the same platform may be entirely governed by a different API version with different field names. Capability discovery must be run per asset class, not just once for the primary instrument type.
Structure your capability manifest with an asset-class dimension: manifest.equity.limit.gtc = supported, manifest.options.limit.gtc = unsupported. When routing an order, look up the asset class, specific capability rather than the global one.
FAQ
How often should I re-run capability discovery?
At minimum, once per quarter as a scheduled maintenance task. Additionally, re-run after every broker API version announcement, after any production error you haven't seen before, and after your broker sends release notes for their API. Build the re-run as an automated script that completes in under 30 minutes and diffs the new results against the stored manifest, you want a fast signal when something changes, not a multi-day manual audit.
What should I do if a required order type is not supported?
Three options, in descending order of preference: (1) synthesize the order type from supported primitives within your adapter, a trailing stop can be emulated as a loop that cancels and replaces a limit order as the price moves; (2) route that order type to a different broker that does support it; (3) reject the order at the adapter boundary with a clear error and let your strategy handle the fallback. Never silently modify the order type without the strategy's knowledge, because the risk profile changes when you swap a stop-limit for a market order.
How do I test rate limits without getting my account flagged?
Use the sandbox environment exclusively for rate limit probing. Most brokers apply rate limits to sandbox accounts the same way they apply them to production accounts, but a sandbox-triggered 429 doesn't affect your production standing. If the broker has no sandbox, rate limit testing gets more delicate, probe during low-activity periods, use a test account separate from your primary trading account, and stay well below where you expect the limit to be rather than deliberately triggering it.
What's the minimum viable capability manifest?
At minimum, record: supported order types (as an enum), supported TIF values per order type, supported asset classes, fractional share support (boolean), minimum order quantity per instrument type, and the sustained rate limit for the order submission endpoint. These seven categories cover the capabilities your adapter needs to make routing and validation decisions. Add tick size, burst limits, and session-level constraints as you discover them.
Can I use a broker's API introspection endpoint instead of empirical testing?
Some brokers provide capability-discovery endpoints that return supported order types and account-level flags. Use these if they exist, they're faster to query than running a full test matrix. But don't trust them exclusively. Introspection endpoints often return static values that lag the API's actual behavior, particularly for recently added or deprecated features. Cross-validate introspection results against empirical tests for the capabilities your strategy critically depends on.
How do I handle a broker that rejects test orders for capability discovery in the sandbox?
Some sandbox environments reject certain order types not because they're unsupported in production but because the sandbox's fill simulator doesn't model them. When you encounter a sandbox rejection, check the broker's sandbox documentation to determine whether it's a sandbox limitation or a production limitation. If ambiguous, try the same order in a small size in a live paper account (if the broker offers one separate from the main sandbox), or contact the broker's developer support. Always document the ambiguity in your manifest rather than assuming the worst or best case.
What's the difference between an order type not being supported and an order type being rejected for a specific instrument?
Not-supported means the broker never accepts that order type anywhere. Instrument-rejected means the order type is valid in general but not for this specific symbol, asset class, or session. The distinction matters because instrument-level rejections are often dynamic, they can change based on market conditions (halt status, SSR) or instrument properties (OTC vs. listed). Record not-supported as a static capability flag in your manifest; handle instrument-rejected as a runtime error that your strategy needs to handle gracefully at the time of submission.
Should I build capability discovery into the adapter startup sequence?
Query the broker's introspection endpoints at startup if they exist, these are fast and confirm that your stored manifest is still broadly valid. Don't run the full empirical test matrix at startup; it takes too long and would delay your system coming online. The full matrix runs offline as a scheduled job. At startup, compare the introspection results against your stored manifest and alert on significant divergence. If the broker has no introspection endpoint, use a single lightweight probe (e.g., submit and immediately cancel one canonical order) to confirm basic connectivity and order flow before going live.
How should discovered capabilities be versioned so a change is detectable?
Persist each discovery run as a dated snapshot rather than overwriting the current manifest, and compare each new run against the previous one. That turns capability discovery into a change feed: a capability disappearing, a limit tightening, or a new order type appearing all surface as a diff rather than as a silent update. Storing the raw responses alongside the derived manifest makes it possible to determine later whether a behavior change came from the broker or from the discovery logic.
References
- Broker Capability Matrix: an interactive tool for laying out the results of your capability discovery testing in a side-by-side comparison across brokers.
- Alpaca Markets: Order Types: Detailed documentation of order types and TIF combinations with constraint tables useful as a reference for a real capability matrix.
- TD Ameritrade API Documentation: Historical reference; Schwab absorbed TD Ameritrade and is migrating the API, illustrating how broker API changes require capability re-validation.
- FINRA Rule 4210 (Margin Requirements): The regulatory basis for margin-account order constraints that show up as capability differences between account types.
- SEC: Trading Basics Investor Bulletin: Background on order types and execution mechanisms relevant to understanding why brokers impose certain constraints.
Educational Disclaimer
This guide is for educational and informational purposes only. It does not constitute financial, investment, or legal advice. Broker APIs change frequently, always verify current capabilities against official broker documentation and empirical sandbox testing before building production integrations.