API guide
Market data API explained: REST, WebSocket, symbols and timestamps
Endpoints are the easy part. The bugs live in four quieter decisions every provider makes for you: what a symbol means, which unit a price is in, which clock a timestamp reads, and how often you may ask.
On this page
- What a market data API actually returns
- How prices travel from the market to your code
- Symbols: the first thing that breaks
- Units and number types
- Timestamps: which clock is this?
- Real-time, delayed and end-of-day data
- REST or WebSocket: pick per job
- Authentication, limits and errors
- A glossary to keep open
- Questions
Key takeaways
- A market data API returns quotes, trades, bars and reference data for traded instruments, over REST when you ask and over WebSocket when you want updates pushed.
- Integrations rarely break on endpoints. They break on symbol formats, price units, timestamp meaning and rate limits.
- TickerLayer serves stocks, forex, crypto, indices, ETFs and commodities with one URL pattern and one x-api-key header.
- A daily bar is stamped at midnight UTC of its session date, not at the close: always check which event a timestamp marks.
- The free tier includes 3,000 REST requests a month, enough to build against real data before you pay.
A market data API is a web service that hands your code the prices of traded instruments and the reference data around them: the current bid and ask, the last trade, historical OHLCV bars, symbol lists and market hours. You call it over REST when you want one answer now, and you hold a WebSocket open when you want every change pushed to you as it happens.
That definition fits every provider. What separates a pleasant integration from a month of quiet bugs is everything around the endpoint, so this guide walks through the parts in the order they tend to break, using TickerLayer for the examples. One request first:
curl -sS "https://api.tickerlayer.com/stocks/snapshot/US:KO" \
-H "x-api-key: $TICKERLAYER_API_KEY"What came back
{
"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 listing market,KOthe ticker. A bareKOreturns400.bid / askThe best price to sell into and to buy from right now, in US dollars.last_priceThe most recent trade. It can sit inside, or briefly outside, the bid and ask.last_timestampWhen that trade happened, in Unix milliseconds, UTC. Not when you asked.prev_closeThe previous session close, the base forchangeandchange_percent.change_percentAlready a percentage: 0.4897 means +0.49%, not +48.97%.
What a market data API actually returns
Market data is the record of what buyers and sellers are doing: the prices they quote, the trades they complete, and summaries of both over time. Around it sits reference data that tells you how to read those prices: which instruments exist, when their markets open, what unit a number is in. A financial data API usually adds slower-moving data such as company fundamentals.
| Data | What it answers | TickerLayer route | Key fields |
|---|---|---|---|
| Quote | What can I buy or sell at right now? | GET /{asset}/quote/{symbol} | bid, ask, bid_size, ask_size, timestamp |
| Last trade | What was the most recent deal? | GET /{asset}/trade/last/{symbol} | price, size, timestamp |
| Snapshot | Quote, last trade and daily change, in one call | GET /{asset}/snapshot/{symbol} | last_price, prev_close, change_percent |
| Bars (OHLCV) | How did the price move over time? | GET /{asset}/agg/{symbol}/1/day/{from}/{to} | o, h, l, c, v, t |
| Symbols | Which instruments can I ask for? | GET /{asset}/symbols | symbol, name |
| Market status | Is this market open, and when does it next open? | GET /markets/status | status, next_open, next_close |
Quotes here are Level 1 data: the best bid and the best ask, with their sizes. Level 2 adds the queue of orders waiting behind them at every price. Most developer APIs, TickerLayer included, serve Level 1, and it is what charts, alerts, dashboards and most trading logic actually consume.
How prices travel from the market to your code
Every price starts as an event somewhere else: an order resting on an exchange, a dealer quote, a trade printed on a venue. A market data feed is the continuous stream of those events from one source. The API sits at the other end and turns many feeds into one consistent interface. What happens in between decides how far you can trust the number.
- Your applicationCharts, alerts, bots, spreadsheets, AI agents.
you - REST and WebSocketAuthentication, entitlements and rate limits in front of
api.tickerlayer.comandstream.tickerlayer.com.delivery - Aggregation layerMaps every source to one symbol format, one unit and one clock, and checks prices before they are served.
normalize - SourcesExchanges, trading venues, dealers and reference feeds, each with its own symbols, units and timestamps.
origin
Providers differ most in the bottom two layers. An exchange-direct feed gives you one venue's raw messages, fast and official, with that venue's licence attached. An aggregated API such as TickerLayer combines sources into derived, indicative prices: not official exchange data, but one format across asset classes and markets, which is what most applications need. If you are weighing those trade-offs, the guide to choosing financial data providers lists the questions to ask, and our data quality benchmarks show how our prices compare with independent references.
Symbols: the first thing that breaks
A symbol looks like a trivial string until you add a second market. KO is unambiguous in New York, but tickers are unique only inside one market, and the same company can list in several. That is why TickerLayer stock symbols carry a market prefix, US:KO or DE:SAP, and why a bare KO returns 400 invalid symbol instead of a guess.
| Asset | Format | Examples |
|---|---|---|
| Stocks | CC:TICKER | US:KO, US:BRK.B, DE:SAP, JP:7203, HK:0700 |
| Forex | Six-letter pair | EURUSD, USDJPY, GBPUSD |
| Crypto | Coin plus quote currency | BTCUSD, ETHUSD, SOLUSD |
| Indices | Generic code | US500, US30, DE40, JP225 |
| ETFs | Unprefixed code | US500ETF, WORLDETF, USGOLD |
| Commodities | Reference code | XAUUSD, WTIUSD, NGASUSD |
Two habits prevent most symbol bugs: normalize user input before it reaches your code (EUR/USD becomes EURUSD, BTC-USD becomes BTCUSD), and validate against the provider's symbol list instead of guessing. The ticker symbol guide covers formats across markets, including numeric codes in Asia and share-class suffixes.
Units and number types
A price is a number plus a unit, and the unit is usually implied. Currency pairs are priced in the second currency, so USDJPY at 157.10 means yen per dollar. Stocks are priced in the currency of their listing. Commodities are where implied units bite: SUGARUSD is quoted in US cents per pound, so 18.54 means 18.54 cents, not dollars. Bond yields come with an explicit "unit": "percent", and the bond snapshot reports the daily move twice, as change in percentage points and as change_bps in basis points.
Number types matter too. REST responses send JSON numbers. The WebSocket stream sends crypto, forex and stock prices as strings ("bid":"82849.99"), which keeps the exact digits but makes float() or Number() your job. And JSON numbers are binary floating point: one captured index snapshot carried prev_close as 7753.800020000001. Round for display, and use a decimal type when you add up money.
Timestamps: which clock is this?
Every TickerLayer price carries a Unix timestamp in milliseconds, UTC: a 13-digit integer such as 1790591112968, which is 10:25:12.968 UTC on 28 September 2026. The format is the easy part. The question to ask of every timestamp is which event it marks.
| Field | Where | What it marks |
|---|---|---|
timestamp | REST quote and last trade | The time of the quote or trade, in Unix milliseconds |
last_timestamp | REST snapshot | The last trade, which can be hours old outside trading hours |
t | Bars | The start of the bar; a daily bar is stamped at 00:00 UTC of its session date |
ts | WebSocket frames | The update; a snapshot frame keeps its original time, so it can be older than its arrival |
next_open, next_close | Market status | ISO-8601 strings in UTC, with the market's local_time alongside |
The daily bar convention catches everyone once. The US:KO bar for Friday 25 September 2026 has t = 1790294400000, which is midnight UTC, although the session ran from 13:30 to 20:00 UTC. Nothing is wrong: the stamp names the session date, not the closing bell. The guide to Unix timestamps in milliseconds has conversion code for every language and the time-zone traps that come with it.
Real-time, delayed and end-of-day data
Real-time data is delivered as soon as practical after the market event, with no deliberate hold. Delayed data is held back on purpose, commonly by 15 minutes, because many licences price live display far above delayed display. End-of-day data arrives once, after the close. A real-time market data API means the first category; the rest of the latency conversation is about how far below a second you truly need to be.
Where kinds of market data sit on the clock
- ~10 µsCo-located exchange feed
- ~100 msStreaming over the public internet
- ~5 sREST polling every 10 s, average wait
- 15 minDelayed display data
- 1 dayEnd-of-day files
TickerLayer's API is real-time, with two qualifications worth stating. The prices are derived and indicative rather than official exchange data. And for stocks, latency varies by market, so a few markets are delayed. The public symbol pages on this website show prices 15 minutes delayed; the API does not.
REST or WebSocket: pick per job
REST
- You ask; the server answers once.
- Best for history, snapshots, page loads and scheduled jobs.
- Each call counts against a per-second limit and a monthly quota.
- Stateless: easy to cache, retry and run from serverless code.
WebSocket
- You subscribe once; the server pushes every update.
- Best for live prices on many symbols, trade tapes and alerts.
- Limited by connections and distinct symbols, not by request count.
- Stateful: you own reconnects, heartbeats and resubscribes.
A WebSocket session is short to set up. Connect to wss://stream.tickerlayer.com/?apiKey=..., wait for the ready frame, and send one message:
{"action": "subscribe", "channels": ["crypto.quotes", "crypto.trades"], "symbols": ["BTCUSD"]}The server confirms with a subscribed frame and starts pushing quotes and trades. For symbols with a recent value it first sends that last-known value marked "snapshot": true, so a screen is not blank while it waits for the first tick; add "snapshot": false for live ticks only. The trade-offs, with the request arithmetic worked through, are in WebSocket vs REST.
Authentication, limits and errors
Send the key in the x-api-key header
Market data APIs authenticate with a key, and the key has to travel somewhere. TickerLayer REST expects it in the x-api-key header on every request. A custom header keeps the key out of URLs, which end up in server logs, browser history and proxy caches; that is also why the older ?apiKey= query form is accepted on REST only as a legacy fallback. The WebSocket upgrade is the exception: browsers cannot set custom headers on a WebSocket, so the stream takes the key as ?apiKey= on the connection URL.
import os
import requests
resp = requests.get(
"https://api.tickerlayer.com/stocks/snapshot/US:KO",
headers={"x-api-key": os.environ["TICKERLAYER_API_KEY"]},
timeout=10,
)
resp.raise_for_status()
snap = resp.json()
print(f'{snap["symbol"]} last {snap["last_price"]} ({snap["change_percent"]:+.2f}% vs {snap["prev_close"]})')const res = await fetch("https://api.tickerlayer.com/stocks/snapshot/US:KO", {
headers: { "x-api-key": process.env.TICKERLAYER_API_KEY },
});
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const snap = await res.json();
console.log(`${snap.symbol} bid ${snap.bid} ask ${snap.ask} last ${snap.last_price}`);US:KO last 88.16 (+0.40% vs 87.81)
US:KO bid 88.15 ask 88.2 last 88.16Keep the key on a server. A key embedded in a web page is visible to anyone who opens the developer tools, and browser calls to the REST API are accepted only from approved origins anyway.
Errors and limits to handle on day one
| Status | Meaning | What to do |
|---|---|---|
| 400 | Malformed request, such as a bare KO or an unsupported bar interval | Fix the request; do not retry |
| 401 | Missing or invalid key | Check the header name and the key |
| 403 | Your plan does not include this data | Upgrade or drop the call; retrying will not help |
| 404 | Unknown symbol or no data | Validate symbols against GET /{asset}/symbols |
| 429 | Per-second limit or monthly quota reached | Honour Retry-After, back off with jitter |
| 503 | Temporary unavailability | Retry with backoff |
Every authenticated response carries X-RateLimit-Limit and X-RateLimit-Remaining for the current one-second window, so a well-behaved client can pace itself before it ever sees a 429. The free tier includes 3,000 REST requests a month, and paid plans are sold per feed. Retry code that tells the two kinds of 429 apart is in 429 Too Many Requests.
A glossary to keep open
- Bid and askThe best price a buyer will pay and the best price a seller will accept. The gap between them is the spread.
- MidThe midpoint of bid and ask. What most charts plot, and a price nobody actually trades at.
- LastThe price of the most recent trade. In a quiet market it can lag the quote by minutes.
- OHLCVOpen, high, low, close and volume for one interval: the bar behind every candlestick.
- SnapshotQuote, last trade and daily change in one response, or the last-known value a stream sends on subscribe.
- TickA single update: one new quote or one new trade. Streams deliver ticks; bars summarize them.
- EntitlementWhat a key may access: which feeds, which markets, which transports.
- AggregationCombining several sources into one price per instrument, in one format.
- SessionThe hours a market trades, including pre-market and after-hours for US stocks.
Go deeper by asset class
- Stock APIQuotes, trades and bars across 20 live stock markets, with market-qualified symbols.
- Exchange rate APILive and historical FX rates, conversion and the spread between bid and ask.
- Crypto price APIAggregated round-the-clock prices, bars and trade streams.
- WebSocket market dataConnect, subscribe, read frames and stay connected through drops.
Questions
What is a market data API?
A web service that returns prices and reference data for traded instruments to your code: quotes, trades, historical bars, symbol lists and market hours. It is usually offered over REST for requests and over WebSocket for streaming.
What is the difference between real-time and delayed market data?
Real-time data is delivered as soon as practical after the market event. Delayed data is held back on purpose, commonly by 15 minutes, usually because a licence for live display costs more.
Is there a free market data API?
Yes. The TickerLayer free tier includes 3,000 REST requests a month with no card required, enough to prototype. WebSocket streaming comes with paid plans, and free accounts can request a trial from the dashboard.
What is the x-api-key header?
A custom HTTP request header that carries your API key. Sending the key in a header rather than in the URL keeps it out of server logs and browser history.
Should I use REST or WebSocket for market data?
Use REST for history, snapshots and occasional lookups, and a WebSocket when you need continuous live prices on more than a few symbols. Most production apps use both.
What is a market data feed?
The continuous stream of quotes and trades from one source, such as an exchange or a trading venue. An API is the interface you use to read one or more feeds.