Contents Lesson 10 of 16

7 min read · practitioner

How do you quote fifty symbols without fifty requests?

A dashboard with forty tickers on it should not make forty API calls every refresh. Both delayed-quote endpoints take several symbols at once, and each does it with a slightly different contract.

Batching on /real-time/{ticker}

The path takes one symbol. The s query parameter takes a comma-separated list of additional ones:

/real-time/AAPL.US?s=SPY.US,EURUSD.FOREX,BTC-USD.CC

Four symbols, one request. The list mixes asset classes freely — US equities, an FX pair and a crypto pair in the same call, each with its own exchange suffix.

Now the detail that breaks client code. The response schema for this endpoint is a oneOf: a single object when you request one symbol, an array of objects when you use s. The shape of the response depends on the contents of your query string. Code that handles the one-symbol case and then acquires a second symbol will fail at the point it tries to read .code off a list.

The robust habit is to always send s, even with a single extra symbol, so you always parse an array — or to normalise immediately on receipt and never let the two shapes propagate.

The endpoint also accepts an ex parameter, an exchange-code filter. It is documented thinly; treat anything you discover through it as unsupported until it appears properly in the specification.

Batching on /us-quote-delayed

This one is built for batching from the start. There is no path symbol at all — s is required and takes the comma-separated list:

/us-quote-delayed?s=AAPL,MSFT,GOOGL

Now read the response before you write anything against it, because it is not the /real-time shape with more rows. It is a different object with different names:

{"meta": {"count": 2},
 "data": {"AAPL.US": {"symbol": "AAPL.US", "exchange": "XNAS", "type": "STOCK",
                      "name": "Apple", "sector": "Information Technology",
                      "bidPrice": 310.75, "askPrice": 310.8,
                      "bidSize": 40, "askSize": 40,
                      "lastTradePrice": 310.8, "lastTradeTime": 1787143931085,
                      "volume": 1479485, "change": 0.77, "changePercent": 0.25,
                      "previousClosePrice": 310.03, ...}},
 "links": {"next": null}}

Three things there will break a first draft. It is an envelope, not an array — {meta, data, links} — so iterating the response gives you three keys. data is an object keyed by symbol, not a list. And the field names are its own: symbol not code, lastTradePrice not close, previousClosePrice not previousClose, changePercent not change_p, lastTradeTime in milliseconds and no gmtoffset at all.

It adds one parameter the other lacks: fields, a comma-separated list of the fields you actually want — using these names. Ask for fields=close,change_p and you get neither, silently, because neither exists here. Ask for what is there:

/us-quote-delayed?s=AAPL,MSFT&fields=lastTradePrice,volume,changePercent

For a hundred symbols on a dashboard refreshing every minute, trimming thirty fields to three is a real reduction in bytes parsed. And note what this endpoint has that nothing else in the course does: a bid and an ask, with their own sizes and timestamps. The opening lesson of this course listed "no bid, no ask, so you cannot tell what it would have cost to transact" among the things a daily bar leaves out. This is where you get it back.

The scope is narrower, though, and stated in the endpoint's own description: US equities, fifteen-minute delayed. For a London or Tokyo symbol you are back on /real-time. Omitting s returns a 422, not a 400.

How many is too many

There is no hard maximum in the specification, and the vendor's own guidance for /real-time suggests keeping a batch to roughly fifteen to twenty symbols. Treat that as the working limit rather than a rule you can safely ignore, because the failure mode of an over-long query string is a truncated or rejected request, not a helpful error naming the symbol it gave up on.

For a watchlist of two hundred, that means chunking: split into batches of fifteen or twenty, issue them in sequence, and reassemble. Which turns a question about batching into a question about rate limits — one request per chunk, and the per-minute ceiling is the thing you will hit first. Course 1 covers that arithmetic.

The accounting nobody mentions

Batching reduces requests, not necessarily quota. Quota on quote endpoints is generally counted per symbol returned rather than per HTTP call, so a twenty-symbol batch is not one unit of consumption. What batching buys you is fewer round trips, less rate-limit pressure, and one consistent moment for the whole set — every row in a batch is fetched together, which matters when you are comparing them.

Try it now

  1. Here is /real-time/AAPL.US alone, then the same path with s=MSFT.US,TSLA.US. Read the labels in the two tables: the first is one object's fields, the second is rows of a list. Diff the two response shapes. That difference is the bug waiting in most first drafts.
Live API response: apple delayed quote
Live API response: batched delayed quotes
  1. Here are the payload sizes of /us-quote-delayed?s=AAPL,MSFT,GOOGL three ways, measured on 28 September 2026 during the US session. Work out the saving from trimming, then read the last row: a request for two fields that do not exist here succeeded, returned neither of them, and trimmed nothing. Note too what came back for changePercent when it was asked for by name. Below the table is the trimmed call as the academy renders it, with fields=lastTradePrice,volume.
fields status bytes what each symbol's entry held
none 200 3,731 the full record, about fifty fields
lastTradePrice,changePercent 200 222 those two keys, with changePercent null on all three
close,change_p 200 3,731 the full record again, with no close and no change_p in it
Live API response: mda1 us quote delayed trimmed
  1. Here is one seventeen-symbol batch, /real-time/AAPL.US?s=…, called at 15:54:53 UTC on Monday 28 September 2026 with every market below open, trimmed to code and timestamp converted to UTC. Check whether every row carries the same timestamp. Where they differ, ask which instrument last traded and when, and which difference is the licence rather than the trading. That is the answer to a question you did not know you were asking.
code timestamp (UTC)
AAPL.US, MSFT.US, NVDA.US, AMZN.US, GOOGL.US, META.US, TSLA.US, JPM.US, F.US, NVR.US, SPY.US, TLT.US 15:39:00
KO.US 15:38:00
VOW3.XETRA 15:37:00
HSBA.LSE 15:38:00
EURUSD.FOREX 15:54:00
BTC-USD.CC 15:54:00