How do you ask for one number instead of twenty years?
A bare call to /eod/{ticker} returns everything the plan allows — potentially decades of rows — when what you wanted was yesterday's close. Two parameters fix that, and one of them changes the shape of the response entirely.
Narrowing the window
from and to on /eod/{ticker} take calendar dates in YYYY-MM-DD form. from=2020-08-24&to=2020-08-28 returns exactly five rows. Both bounds are inclusive, and a range that contains no trading sessions returns an empty array rather than an error, which is a normal answer and not a failure.
Now the trap, and it is a genuine one. The same two parameter names mean different things on different endpoints.
- On
/eod/{ticker}they are dates:from=2020-08-24. - On
/intraday/{ticker}they are UNIX timestamps in seconds, UTC:from=1627896900. - On
/ticksthey are UNIX timestamps in seconds too — while the timestamps that come back in the response are in milliseconds. - On
/exchange-details/{EXCHANGE_CODE}they filter something else again: the holiday calendar, defaulting to six months either side of today.
Four endpoints, one pair of names, four contracts. Passing 2020-08-24 where seconds are expected does not throw a helpful error; it silently produces something you did not ask for. Read the parameter table for each path rather than assuming the family is consistent.
Asking for a single value
/eod/{ticker} also accepts a filter parameter with six values: last_date, last_open, last_high, last_low, last_close, last_volume.
Use it and the response is no longer an array of objects. A live call for Apple with to=2020-08-28 and filter=last_close returns this, in its entirety:
499.23
A bare JSON number. Not {"close": 499.23}, not a one-element array. If your client code assumes it can iterate the response, adding filter will break it — and the break happens at the parsing layer, far from the line that added the parameter.
Two things worth noting about that value. It is the raw close, not the adjusted one; there is no last_adjusted_close in the enum. And "last" means last within the requested window, so filter composes with from and to rather than always meaning today.
Why any of this matters beyond tidiness
Two reasons, and neither is aesthetic.
Cost. Both the daily quota and the per-minute rate limit are counted in requests, so the discipline that matters is fetching each range once and caching it, not trimming bytes. But payload size is real work for your process: a twenty-year history parsed to answer "what closed yesterday" is thousands of objects allocated and discarded. Course 1 covers how the two limits interact.
Reproducibility. A request with both from and to pinned describes a fixed window of history. Re-run it in a month and the date, open, high, low, close and volume fields will be identical. adjusted_close will not, for the reason the previous lesson established: every new dividend rewrites it. A request with no to is not reproducible at all, because "now" moved.
If you want a result you can hand to somebody else and have them reproduce, pin both bounds, record which day you fetched it, and say which close column you used.
Try it now
- Call
/eod/AAPL.USwithfrom=2020-08-24&to=2020-08-28, then withfilter=last_closeadded. Note that the second response is not JSON your row parser can handle.
- Here is the same endpoint with a
fromandtothat contain only a weekend,/eod/AAPL.US?from=2026-09-26&to=2026-09-27&fmt=json, called on 28 September 2026. The status was 200 and this is the whole body. Decide now how your code should tell it apart from a range that should have held rows.
[]
- Write down the
from/tounits for the daily, intraday and tick endpoints on one line, without scrolling up. That line will save you an afternoon.