Tradovate API /product/find Returns 404
You fired a request at product/find and got a flat 404 back. The endpoint isn't missing, the request is shaped wrong, here's the exact GET and query-string fix.
You fired a request at product/find, and instead of a tidy JSON payload the server threw back a flat 404. Nothing here, it says. But the endpoint isn't missing. In practice that 404 almost always means the request is shaped wrong, not that the route doesn't exist. Nine times out of ten it comes down to one of two mistakes: you sent your parameters in a JSON body instead of the URL, or you're pointing at the wrong host or path. Fix the shape of the call and product/find (plus its close cousin contract/find) start handing you data again.
Here's the short version, then the why and the how.
Quick fix: Call
product/findas a GET with the symbol in the query string,GET https://demo.tradovateapi.com/v1/product/find?name=ES, not a POST with a JSON body. To get the actual tradable contract, usecontract/find?name=ESU6. Both take the same parameters.
Why the 404 happens
A 404 on this call is misleading because we're trained to read it as “this URL doesn't exist.” On the Tradovate REST API, though, the same status shows up when the router can't match the request you actually sent to a real operation. A handful of specific mistakes cause it.
You sent a JSON body instead of a query string. This is the big one. product/find is a read operation, and Tradovate expects read operations to be GET requests with parameters tacked onto the URL. If you POST something like {"name":"es","isAutomated":true} as a JSON body, the request never resolves to the find operation and you get a 404. Two things are wrong there at once: the body-versus-query-string shape, and the extra isAutomated field that find doesn't accept in the first place. Strip both.
You dropped the version prefix or mistyped the host. Every REST call lives under /v1/. The base is https://demo.tradovateapi.com/v1 for simulation and https://live.tradovateapi.com/v1 for live. Leave out the /v1, hit api.tradovate.com (that's the documentation site, not the API), or fat-finger the subdomain, and there's no matching route, 404.
You changed the casing or spelling of the path. The path is two parts: an entity and an operation, joined by a slash, like product/find or contract/find. Write Product/Find, products/find, or product/search and none of them resolve.
You're calling an operation that isn't implemented on that transport. Some operations exist over the WebSocket but not the plain REST route, and vice versa. If you copy a call meant for one and fire it at the other, you'll see a 404 with a body that literally names the missing operation, such as "Not found: md/getChart". That's your clue that the route is fine but the transport is wrong.
One thing a 404 is not: an authentication problem. If your access token is missing or expired, you get a 401, not a 404. So if you're staring at a 404, don't burn time regenerating tokens, look at the request shape and the URL first.
The fix: GET with a query string
Rebuild the call as a GET and move the symbol into the query string. That single change resolves the overwhelming majority of these 404s.
GET https://demo.tradovateapi.com/v1/product/find?name=ES
Authorization: Bearer <your-access-token>
Accept: application/json
Swap ES for whatever product root you're after, MES, NQ, MNQ, CL, and so on. The response is the product record for that instrument: its id, name, product type, exchange, tick size, and value-per-point. Notice there's no request body at all. Nothing to serialize, nothing to get wrong.
If you were using a client library or a bridge that builds the request for you and you're still seeing 404s, check what it's actually sending on the wire. A surprising number of “the API is broken” moments turn out to be a helper quietly wrapping your parameters in a POST body. Point it at GET, and the same symbol lookup that failed a second ago comes back clean.

Get the tradable contract with contract/find
product/find tells you about the instrument family. It won't tell you which contract to actually route an order to, because a product doesn't expire, a contract does. For that, reach for contract/find, which takes the exact same query parameters:
GET https://demo.tradovateapi.com/v1/contract/find?name=ESU6
The name here is the full contract symbol, not just the root. Tradovate builds it from three pieces with no spaces: the product root, a single month code, and the last digit of the year. So ESU6 is the E-mini S&P 500 for U (September) 6 (2026). Change the month letter and year digit as contracts roll, the quarterly equity index months are H, M, U, and Z (March, June, September, December). The front month rotates through the year, so confirm the current active contract rather than hard-coding one that's about to expire.
Feed contract/find a symbol that doesn't exist or has already expired and you may get an empty result rather than a clean contract, another reason to resolve the live front month first instead of guessing. Once you have the contract id back, that's the value you hand to order placement, position lookups, and market-data subscriptions.

When you don't know the exact symbol
What if you don't have the precise contract code and you just want to search? First, adjust your expectations: there is no public “give me every symbol” endpoint. The API is built around targeted lookups, and it expects you to cache what you fetch rather than pull a giant list on every run.
Two practical routes:
- Type-ahead suggest. Tradovate has a contract suggestion endpoint that behaves like the search box in the platform, you pass a partial text string and a result limit, and it returns matching contracts. It's the cleanest way to turn “the user typed
MNQ” into a real, current contract. Confirm the exact parameter names in the current API reference before wiring it in, since the suggest endpoints use short single-letter keys. - Product first, then contract. Look up the product with
product/find?name=NQ, then resolve the active contract for it. This two-step keeps you working with documented, stable operations.
You may run across a contract/list route in the wild. It exists, but it's undocumented and not recommended, it isn't a supported “list everything” call, and building on it invites breakage. Stick to contract/find and the suggest endpoint, cache the results, and refresh your cache around each contract roll.
A 90-second checklist
Before you file a bug report, walk this list. It clears nearly every product/find 404.
| Check | What "good" looks like |
|---|---|
| HTTP method | GET, not POST |
| Parameters | In the query string (?name=ES), not a JSON body |
| Extra fields | No isAutomated or other order-only fields on a find call |
| Base URL | demo.tradovateapi.com/v1 or live.tradovateapi.com/v1, with the /v1 |
| Path spelling | Exactly product/find / contract/find, lowercase |
| Host | Not api.tradovate.com (that's the docs site) |
| Transport | REST route over HTTPS, not a WebSocket-only operation |
If everything above checks out and you still get a 404 specifically on product/find while other GET calls work, capture the raw request and response and take it to Tradovate's API support, but that's rare. Almost every time, the problem is one of the rows above.
Worth knowing which errors are not this one: a 401 means your token is stale or missing (renew it before it expires), and a “symbol is inaccessible” or 403 on a quote request means a market-data entitlement issue, not a lookup problem. Contract and product lookups themselves only need a valid token, no data subscription required.

Want the symbol lookup handled for you?
Wiring up token renewal, front-month resolution, and per-symbol contract lookups is the kind of plumbing that eats a weekend and then breaks on the next contract roll. If your real goal is to fire a TradingView alert and have it land as a live Tradovate order, without babysitting the REST layer, you can skip the raw API entirely and let a bridge map symbols and route orders for you.
Automate your Tradovate orders from TradingView without touching the raw API and let PickMyTrade handle symbol lookup and order routing for you.
Skip the Raw API
Automate your Tradovate orders from TradingView without touching the raw API. PickMyTrade handles symbol lookup and order routing for you.
Start Your Free 5-Day TrialFrequently Asked Questions
Almost always because the request is shaped wrong, not because the route is missing. The most common trigger is sending your symbol in a JSON body instead of the URL query string, or adding fields the endpoint doesn't accept. It's a GET call, so pass the symbol as a query string: GET /v1/product/find?name=ES. A missing /v1/ prefix, the wrong host, or a typo in the path will also produce a 404.
product/find returns the product, the instrument family, like ES for the E-mini S&P 500. contract/find returns a specific tradable contract with an expiration, like ESU6 for September 2026. They take the same query parameters. Use product/find to look up the instrument, then contract/find to get the exact contract you'll trade or subscribe to.
No. There's no public list-all-symbols endpoint. The API expects you to look up what you need with contract/find or the type-ahead suggest endpoint and cache the results. A contract/list route exists but is undocumented and not recommended, so build your workflow around targeted lookups instead.
No. contract/find and product/find return reference data and work with just a valid access token. A market-data subscription only matters when you subscribe to live quotes. If a lookup succeeds but a quote request fails, that's a data-entitlement issue, not a contract-search problem.
This guide is for educational and informational purposes only and is not financial, investment, or trading advice. Trading futures and other leveraged products carries a substantial risk of loss and is not suitable for every investor. PickMyTrade is an independent third-party automation platform and is not affiliated with, endorsed by, or sponsored by Tradovate, Inc. or Bookmap. All related names, logos, and trademarks are the property of their respective owners. Platform features and steps change over time, so always confirm the current process in the official platform documentation before acting.