API guide
Stock API guide: real-time and historical stock prices, with code
Most stock APIs are a US ticker list with a price attached. A useful one also tells you which market a symbol trades in, what time each price is from, and which close a daily bar carries.
On this page
- What a stock price API returns: one route per question
- Stock symbols: why it is US:KO and not KO
- Real-time stock prices: quote, trade and snapshot
- Historical stock data: bars, intervals and the official close
- Real-time stock API streams over WebSocket
- One stock market API for 20 markets
- How to choose a stock data API
- What to build next
- Questions
Key takeaways
- A stock API returns five kinds of data: the quote (bid and ask), the last trade, a snapshot that combines them, OHLCV bars for history, and a live stream over WebSocket.
- TickerLayer names every stock with its market (`US:KO`, `DE:SAP`), so one ticker listed in two markets can never collide; a bare `KO` is rejected with 400 invalid symbol.
- Twenty live stock markets share one schema: the same routes, field names and Unix millisecond timestamps for New York, Frankfurt, Tokyo or Istanbul.
- US daily bars carry the official open and close with consolidated volume; intraday bars cover the regular session, 09:30 to 16:00 New York time.
- REST sends numbers while WebSocket stock frames send prices as strings, so convert explicitly before doing arithmetic.
A stock API is a web service that returns stock market data as JSON: the current bid and ask, the last trade, open-high-low-close bars for history, and a live stream of quotes and trades. It is the equities slice of a market data API: your code asks for a symbol and gets numbers back, with no scraping and no chart parsing. With TickerLayer, one request for Coca-Cola looks like this:
curl -sS "https://api.tickerlayer.com/stocks/snapshot/US:KO" \
-H "x-api-key: $TICKERLAYER_API_KEY"A stock snapshot, field by field
{
"symbol": "US:KO",1
"bid": 88.11,
"ask": 88.24,
"bid_size": 400,
"ask_size": 1000,
"last_price": 88.24,3
"last_timestamp": 1790589160160,4
"prev_close": 87.81,5
"change": 0.43,
"change_percent": 0.4897,6
"last_size": 150
}
symbolMarket-qualified:USis the market,KOthe ticker.bid / askBest standing prices to sell and to buy. Thirteen cents apart because this is a pre-market quote.last_priceThe most recent trade, here a 150-share pre-market print.last_timestampWhen that trade happened, in Unix milliseconds UTC: 09:52:40 UTC, 05:52 in New York.prev_closeThe previous session's official close, Friday 2026-09-25.change_percentLast price against the previous close, in percent.
That response is the whole integration in miniature: a symbol with a market prefix, both sides of a quote, the last trade, and Unix millisecond timestamps on everything. The rest of this guide takes each piece in turn: what the endpoints return, how symbols work across 20 markets, how historical bars are built, and when to stream instead of poll.
What a stock price API returns: one route per question
Every stock data API boils down to the same handful of questions, and TickerLayer answers each with one route. The paths are identical across asset classes (swap stocks for forex, crypto, indices, etfs or commodities), so what you learn here carries over.
| Question | Route | Returns |
|---|---|---|
| What can I buy or sell at right now? | GET /stocks/quote/{symbol} | bid, ask, sizes, timestamp |
| What was the last deal? | GET /stocks/trade/last/{symbol} | price, size, timestamp |
| Everything at once, with the change? | GET /stocks/snapshot/{symbol} | Quote, last trade, prev_close, change, change_percent |
| What was yesterday's bar? | GET /stocks/agg/{symbol}/prev | The last completed daily OHLCV bar |
| What did it do over a period? | GET /stocks/agg/{symbol}/{mult}/{span}/{from}/{to} | OHLCV bars from 1 minute to 1 day |
| Which symbols can my key use? | GET /stocks/symbols?market=US | symbol, base_symbol, market, name |
The same data also streams over WebSocket on stocks.quotes, stocks.trades and stocks.agg (settled bars), plus stocks.status for US halts and resumptions. Errors are predictable: 400 for a malformed symbol or interval, 401 for a missing key, 403 when your plan does not include the market, 404 for an unknown symbol, and 429 when you exceed the per-second limit or the monthly quota. Every authenticated response carries x-ratelimit-limit and x-ratelimit-remaining, so a client can pace itself before it ever sees a 429.
Stock symbols: why it is US:KO and not KO
Tickers are not unique across the world. Three letters are cheap and markets reuse them, and a numeric code like 2330 means nothing until you know it trades in Taipei. So TickerLayer qualifies every stock with an ISO country code: US:KO, DE:SAP, JP:7203, TR:THYAO. A bare ticker is rejected rather than guessed:
GET /stocks/quote/KO 400 {"statusCode":400,"message":"invalid symbol"}
GET /stocks/quote/US:KO 200 {"symbol":"US:KO","bid":88.11,"ask":88.3,...}The colon goes into the path as is; clients that percent-encode it as %3A work too. If you inherit a spreadsheet of bare or oddly formatted tickers, POST /symbols/coverage maps KO to US:KO, 0700.HK to HK:0700 and BTC-USD to BTCUSD in one call. The ticker symbol explainer covers the naming schemes you will meet in the wild.
| Code | Market | Example symbols |
|---|---|---|
| US | United States | US:KO, US:JPM, US:DIS |
| DE | Germany | DE:SAP, DE:BMW, DE:ALVDE |
| FR | France | FR:MC, FR:AIR, FR:TTE |
| ES | Spain | ES:IBE, ES:SAN, ES:BBVA |
| IT | Italy | IT:ISP, IT:UCG, IT:ENI |
| SE | Sweden | SE:SAAB |
| RO | Romania | RO:TLV, RO:H2O, RO:SNP |
| TR | Turkey | TR:THYAO, TR:ASELS, TR:KCHOL |
| SA | Saudi Arabia | SA:2222, SA:1120, SA:2010 |
| AE | United Arab Emirates | AE:EMAR, AE:DIB |
| JP | Japan | JP:7203, JP:6758, JP:6501 |
| HK | Hong Kong | HK:0700, HK:0005, HK:0388 |
| CN | China | CN:600519, CN:300750 |
| KR | South Korea | KR:005930, KR:000660 |
| TW | Taiwan | TW:2330, TW:2303 |
| IN | India | IN:RELIANCE, IN:TCS |
| TH | Thailand | TH:PTT, TH:AOT |
| BR | Brazil | BR:PETR4, BR:ABEV3 |
| MX | Mexico | MX:WALMEX, MX:AMXB |
| AR | Argentina | AR:YPFD, AR:GGAL |
Latency varies by market (some are real-time, some delayed), and each market is bought separately, so check the stocks documentation for the current list before you promise a market to your own users.
Real-time stock prices: quote, trade and snapshot
A quote is the best bid and ask standing right now. A trade is a deal that already happened. They move independently: a quiet stock can show a fresh quote next to a trade from forty minutes earlier. That is exactly what the snapshot above shows: the quote was current when it was taken, around 10:34 UTC, while the last trade was a pre-market print from 09:52.
| Feature | Quote | Last trade | Snapshot | Bar |
|---|---|---|---|---|
| Answers | What can I trade at now? | What did the last deal print at? | Where are we versus yesterday? | What happened in this window? |
| Time field | timestamp | timestamp | last_timestamp | t, the bar start |
| Changes when | An order improves or leaves | A trade prints | Either of those | The window closes |
| Best for | Spreads, fill estimates | Ticker tapes | Watchlists, dashboards | Charts, backtests |
The snapshot is the endpoint most apps want: one call returns the quote, the last trade, the previous close and the change since. It also answers at any hour. Outside the session a stream may have nothing new to send, but GET /stocks/snapshot/{symbol} returns the last known values, so a page that loads at 03:00 still has a price to show. A watchlist is a loop:
import os
import requests
API = "https://api.tickerlayer.com"
HEADERS = {"x-api-key": os.environ["TICKERLAYER_API_KEY"]}
for symbol in ["US:KO", "US:JPM", "US:DIS"]:
r = requests.get(f"{API}/stocks/snapshot/{symbol}", headers=HEADERS, timeout=10)
r.raise_for_status()
s = r.json()
change = s.get("change_percent") # null when there is no previous close
change_text = f"{change:+.2f}%" if change is not None else "n/a"
print(f'{s["symbol"]:<7} {s["last_price"]:>8.2f} {change_text:>8}')US:KO 88.16 +0.40%
US:JPM 341.00 -0.60%
US:DIS 105.97 -0.17%Historical stock data: bars, intervals and the official close
History comes as OHLCV bars: open, high, low, close and volume per window. Six intervals are available (1, 5 and 15 minutes, 1 and 4 hours, 1 day), and each request names a UTC date range that is inclusive at both ends: GET /stocks/agg/US:KO/1/day/2026-09-14/2026-09-26 returns ten daily bars. One regular US session produces this many bars at each size:
- 390one-minute bars
- 26fifteen-minute bars
- 7hourly bars, the last one a half hour
- 1daily bar with the official close
Three rules separate a correct price history from a plausible-looking one:
- Daily bars carry the official open and close, with consolidated volume. On 2026-09-25 Coca-Cola's regular-session minute bars added up to 8,997,796 shares while the daily bar reported 12,261,067. The gap is volume the minute grid does not cover, such as the closing auction and pre-market and after-hours trading.
- Intraday US bars cover the regular session, 09:30 to 16:00 New York time. The bar for the session in progress is included, so the newest row can still change until its window closes.
- Timestamps are bar starts in UTC. A daily bar's
tis midnight UTC of the session date, not the moment of the close. Convert it to New York time and Friday's bar lands on Thursday evening.
The historical stock data guide goes deeper on all three, plus split adjustments and a CSV exporter, and the Python stock prices tutorial turns the same routes into a pandas DataFrame with error handling.
Real-time stock API streams over WebSocket
Polling a snapshot every few seconds works for a handful of symbols, then burns requests. A stream inverts the flow: you connect once to wss://stream.tickerlayer.com, wait for the ready frame, subscribe, and the server pushes each quote and trade as it happens.
{"action": "subscribe", "channels": ["stocks.quotes", "stocks.trades"], "symbols": ["US:KO", "US:JPM"]}A live stocks.quotes frame
{
"type": "quote",
"channel": "stocks.quotes",
"asset": "stocks",
"symbol": "US:KO",
"bid": "88.11",
"ask": "88.24",
"bid_size": "400",
"ask_size": "1000",
"ts": 17905915280963
}
type / channelRoute frames on these two fields; system and error frames share the socket.bid / askStrings on the stocks, forex and crypto channels. Convert withfloat()orNumber().tsEvent time in Unix milliseconds. Stream frames usets, REST usestimestamp.
Two details trip people up. Prices arrive as strings, so "88.11" + 1 fails in Python and concatenates in JavaScript. And the snapshot replayed on subscribe only covers recent values for US equities, so before the open you may see nothing until the first live tick: seed your screen with the REST snapshot. WebSocket access comes with paid plans. The WebSocket market data guide covers connecting, reconnecting and backfilling in detail.
One stock market API for 20 markets
The part many stock APIs treat as an afterthought is everything outside the US. The same routes and fields serve every live market, so a portfolio of New York, Frankfurt and Tokyo names is one loop, not three integrations. This Node.js script asks each for its last completed daily bar:
// Node 18 or newer (global fetch). Run: node prev_close.mjs
const API = "https://api.tickerlayer.com";
const headers = { "x-api-key": process.env.TICKERLAYER_API_KEY };
for (const symbol of ["US:KO", "DE:SAP", "JP:7203"]) {
const res = await fetch(`${API}/stocks/agg/${symbol}/prev`, { headers });
if (!res.ok) {
console.error(`${symbol}: HTTP ${res.status} ${await res.text()}`);
continue;
}
const { result } = await res.json();
const session = new Date(result.t).toISOString().slice(0, 10); // UTC midnight = session date
console.log(`${symbol.padEnd(8)} session ${session} open ${result.o} close ${result.c}`);
}US:KO session 2026-09-25 open 88.16 close 87.81
DE:SAP session 2026-09-25 open 184.42 close 185.92
JP:7203 session 2026-09-25 open 2990 close 2989.5All three bars carry the same session date even though the sessions ran at completely different hours. Keep that date as a date, and convert intraday timestamps to the market's own time zone only when you display them.
Three regular sessions on one UTC clock
Hours in UTC
Calendars differ as much as clocks. Between 2026-09-21 and 09-26, JP:7203 returned two daily bars, not five, because Tokyo was closed Monday to Wednesday for public holidays. GET /markets/holidays and GET /markets/status let a scheduler know that in advance instead of treating a missing bar as an outage.
How to choose a stock data API
Ask these before you integrate
- Symbols carry a market, so two listings with the same ticker never collide.
- Every price has a timestamp in a documented unit and time zone.
- Daily bars say which close they use: the official close or the last trade.
- Intraday history says which session it covers and whether the newest bar is still forming.
- History depth per plan is published before you pay.
- The license says whether you may show prices to other people or only use them internally.
- Rate limits are readable from response headers, not discovered by getting blocked.
- The schema covers the markets you will need next year, not only the US.
Free tiers deserve their own scrutiny, because request caps, delays and display rights vary more than prices do. The free stock API guide sorts the common free-tier types honestly. If you need company data next to prices, the stock float explainer shows the fundamentals add-on in use.
What to build next
- Pre-market and after-hoursWhy quotes widen outside 09:30 to 16:00 and what extended sessions can tell you.
- Trading haltsHow US halts and volatility pauses arrive on
stocks.status, and what to do with them. - Stock prices in Google SheetsLive prices in a spreadsheet without copy and paste.
- Stock prices in ExcelA workbook that refreshes from the REST API.
Questions
What is the best API for stock prices?
The one whose coverage, timestamps and license match your use. Check that symbols carry a market, that daily bars state which close they use, that history depth is published, and that the license allows the way you will display the data.
Is there a free stock API?
Yes. TickerLayer's free tier includes 3,000 REST requests a month with no card. Free tiers in general restrict volume, speed and commercial display, so read the limits before you build on one.
How do I get real-time stock prices from an API?
Call a quote or snapshot endpoint for a spot value, or subscribe to a WebSocket channel such as stocks.quotes to receive every update as it happens. Polling suits a few symbols; streaming suits many.
Which stock markets does the TickerLayer stock API cover?
Twenty live markets, including the US, Germany, France, Spain, Italy, Japan, Hong Kong, China, India, South Korea, Taiwan, Brazil, Mexico, Turkey and Saudi Arabia. Symbols use a market prefix such as DE:SAP or JP:7203.
Does a stock API include pre-market and after-hours prices?
TickerLayer's live US quotes and snapshots carry pre-market activity (this guide's examples were captured before the open), while historical intraday bars over REST cover the regular session. On WebSocket, stocks.agg with session: "extended" adds pre-market and after-hours bars.
Why does my stock API request return 400 invalid symbol?
The symbol is missing its market prefix. Use US:KO, not KO; POST /symbols/coverage converts bare and differently formatted tickers in bulk.