On this page
The shortest correct implementation
/stable/quote for one detailed snapshot.
Keep the API key on your server, set a timeout, reject empty arrays, validate the response timestamp, cache by market session, and retry only 429 or 5xx responses. Use a historical endpoint for charts—do not assemble a chart from repeated quote calls.
Developers building dashboards, alerts, research pipelines, AI tools or portfolio features with FMP price data.
An FMP API key, a server runtime, an explicit freshness target, and a decision on adjusted versus unadjusted history.
Pick the endpoint from the job, not the name
“Stock price” can mean a latest snapshot, a compact watchlist refresh, daily candles or minute bars. Those are different payloads with different cost and freshness profiles.
| Need | Stable endpoint | Use it when | Watch for |
|---|---|---|---|
| Detailed latest quote | /quote?symbol=AAPL | You need price, change, ranges and volume. | Larger payload. |
| Compact latest quote | /quote-short?symbol=AAPL | You only need symbol, price and volume. | Less context for validation. |
| Many symbols | /batch-quote/batch-quote-short | Watchlists or scheduled portfolio refreshes. | Plan availability and response size. |
| Daily history | /historical-price-eod/full | Charts, returns and backtests. | Adjustment policy. |
| Intraday bars | /historical-chart/1min/5min · /15min · /30min · /1hour | Intraday charts and indicators. | Plan, history depth and timezone. |
| Extended hours | /aftermarket-quote/aftermarket-trade | You explicitly label extended-session data. | Never blend silently with regular close. |
“Real time” is not a single guarantee
Exchange entitlement, endpoint, plan and market session determine whether a value is real time, delayed, after-market or end of day. Your UI should never infer freshness from the word “quote.”
When the market observation occurred. Use the response timestamp and normalize it to UTC.
When your service received it. Store separately so latency and cache age remain measurable.
A Friday close is expected on Saturday. “Old” is not always “stale”; compare against the exchange calendar.
Document currency, venue and corporate-action adjustment before combining symbols or computing returns.
Call the FMP quote API safely
Load FMP_API_KEY from an environment variable or secret manager. FMP supports an apikey header and a query parameter; the header reduces accidental exposure in URLs and logs.
Set a timeout, encode the symbol, cap concurrency and record endpoint latency.
HTTP 200 is not enough. Reject an empty array, missing symbol, non-finite price or an unacceptable timestamp.
curl --fail --silent --show-error \
--get "https://financialmodelingprep.com/stable/quote" \
--data-urlencode "symbol=AAPL" \
--header "apikey: $FMP_API_KEY"import os, time, requests
def get_quote(symbol: str) -> dict:
response = requests.get(
"https://financialmodelingprep.com/stable/quote",
params={"symbol": symbol.upper()},
headers={"apikey": os.environ["FMP_API_KEY"]},
timeout=8,
)
response.raise_for_status()
rows = response.json()
if not isinstance(rows, list) or not rows:
raise ValueError(f"No FMP quote returned for {symbol}")
quote = rows[0]
price = float(quote["price"])
event_time = int(quote["timestamp"])
if price <= 0 or time.time() - event_time > 20 * 60:
raise ValueError("Invalid or unexpectedly stale quote")
return {
"symbol": quote["symbol"],
"price": price,
"currency": quote.get("currency"),
"volume": quote.get("volume"),
"eventTime": event_time,
"retrievedAt": int(time.time()),
"source": "fmp",
}type Price = {
symbol: string; price: number; volume?: number;
eventTime: number; retrievedAt: number; source: "fmp";
};
export async function getQuote(symbol: string): Promise<Price> {
const key = process.env.FMP_API_KEY;
if (!key) throw new Error("FMP_API_KEY is missing");
const url = new URL("https://financialmodelingprep.com/stable/quote");
url.searchParams.set("symbol", symbol.toUpperCase());
const response = await fetch(url, {
headers: { apikey: key },
signal: AbortSignal.timeout(8_000),
});
if (!response.ok) throw new Error(\`FMP returned \${response.status}\`);
const rows: unknown = await response.json();
if (!Array.isArray(rows) || !rows.length) {
throw new Error(\`No quote returned for \${symbol}\`);
}
const q = rows[0] as Record<string, unknown>;
if (!Number.isFinite(Number(q.price)) || !Number.isFinite(Number(q.timestamp))) {
throw new Error("Invalid quote payload");
}
return {
symbol: String(q.symbol),
price: Number(q.price),
volume: q.volume == null ? undefined : Number(q.volume),
eventTime: Number(q.timestamp),
retrievedAt: Math.floor(Date.now() / 1000),
source: "fmp",
};
}Normalize a price into evidence
Do not pass the provider payload through your entire application. Create a small internal contract and retain the raw response for debugging or audit where policy permits.
| Field | Why it belongs | Validation |
|---|---|---|
symbol + exchange | A ticker alone can be ambiguous. | Match requested instrument and venue. |
price + currency | A number without denomination is unsafe. | Finite, positive and expected currency. |
eventTime | Supports freshness and ordering. | Valid epoch; compare with session calendar. |
retrievedAt | Measures transport and cache age. | Set by your service, not the provider. |
adjustment | Prevents mixed historical series. | Explicit enum: raw, split or dividend adjusted. |
source | Preserves provenance for agents and audits. | Provider + endpoint + request ID if available. |
Choose adjustment before you calculate
FMP documents full and light end-of-day history, plus non-split-adjusted and dividend-adjusted variants. The right series depends on the question.
Prefer a consistently adjusted series so splits or distributions do not look like unexplained price crashes.
Use actual historical traded prices and model splits, dividends, fees and execution separately.
Persist the adjustment method, interval, timezone and requested date range with every stored dataset.
Production controls that matter
Use a short TTL for an open-market watchlist, longer TTL outside the session, and immutable caching for completed historical bars.
Batch reduces request count but increases payload size and blast radius. Split very large universes into bounded chunks.
Retry 429 and 5xx with exponential backoff, jitter and a maximum attempt count. Do not retry invalid symbols or authentication failures.
Track latency, status, empty-result rate, quote age, cache hit rate and provider spend. Alert on behavior, not only transport errors.
Validation checklist
- API key is absent from browser bundles, URLs, analytics and application logs.
- A valid symbol returns a non-empty array and the expected symbol.
- An invalid symbol, expired key, timeout and 429 all follow tested error paths.
- Freshness thresholds account for weekends, holidays and extended sessions.
- Historical tests cover a known split or dividend and document adjustment behavior.
- Displayed or redistributed data complies with the applicable FMP license.
Common failure modes
| Symptom | Likely cause | What to do |
|---|---|---|
| HTTP 200, empty array | Invalid or unsupported symbol. | Treat as not found; verify symbol and exchange. |
| 401 / 403 | Missing key, invalid key or plan entitlement. | Stop retrying; check secret injection and plan. |
| 429 | Rate limit or quota reached. | Honor retry guidance, back off, batch and cache. |
| Quote looks stale | Closed market, delayed entitlement or cached data. | Compare event time with exchange session and retrieval time. |
| Chart has a sudden cliff | Split/dividend or mixed adjustment policies. | Inspect corporate actions and rebuild one consistent series. |
| Daily bars shift dates | UTC/local timezone conversion. | Store UTC plus exchange timezone; format only at the edge. |
Use a capability layer when the workflow must choose
A direct FMP call is appropriate when the provider and schema are fixed. QVeris becomes useful when an agent must discover an available capability, inspect its current input contract, invoke it consistently, preserve evidence or fall back across providers.
Search for a stock quote or historical-price capability using intent, market and freshness constraints.
Read the live schema before calling. Confirm symbol format, required fields and output provenance.
Invoke with validated arguments, then apply the same normalization and freshness rules described above.
Inspect Financial Modeling Prep in QVeris → · Read the REST API reference →
Match the plan to frequency and history
FMP pricing changes. As verified on July 30, 2026, the published plans list: Free at 250 calls/day; Starter at $22/month billed annually and 300 calls/minute; Premium at $59/month and 750 calls/minute; Ultimate at $149/month and 3,000 calls/minute. Intraday depth, global coverage, batch access and bandwidth also vary.
FMP’s pricing page states that displaying or redistributing data requires an applicable Data Display and Licensing Agreement. Verify the current plan and terms before purchase or launch.
FMP stock price API questions
Is the FMP stock price API real time?
It depends on the endpoint, exchange coverage, entitlement and plan. Treat real-time, delayed, after-market and end-of-day data as different contracts, and validate the response timestamp.
Which endpoint returns the latest stock price?
Use /stable/quote for a detailed current snapshot or /stable/quote-short when you only need symbol, price and volume.
How do I request prices for multiple stocks?
Use batch-quote for full snapshots or batch-quote-short for compact results. Check plan availability and split very large universes into bounded chunks.
Does FMP provide historical stock prices?
Yes. FMP documents full, light, non-split-adjusted and dividend-adjusted end-of-day endpoints, plus intraday chart intervals from one minute to one hour.
Should I use adjusted or unadjusted prices?
Use a consistently adjusted series for return calculations and chart continuity. Use actual unadjusted traded prices for execution reconstruction, with corporate actions modeled separately.
Can I expose the API key in browser code?
No. Keep it in a server-side environment variable or secret manager and proxy requests through your backend.
How should I handle FMP rate limits?
Cache identical requests, batch symbols where appropriate, cap concurrency, and retry only transient 429 and 5xx responses with exponential backoff and jitter.
When should I put QVeris in front of FMP?
Use QVeris for capability discovery, inspected schemas, unified invocation or provider fallback. If your integration is permanently tied to one FMP endpoint, a direct server-side call may be simpler.
Verify against the live documentation
Make every price explainable
Start with the correct FMP endpoint. Add QVeris when the workflow needs discovery, schema inspection or provider-aware capability routing.

