The Bulk Fundamentals API downloads fundamental data for many companies in a single request, instead of calling the single-ticker Fundamentals API symbol by symbol. It is built for keeping a local fundamentals database in sync. Two endpoints cover different needs: the bulk endpoint lets you select specific symbols, paginate, and choose CSV or JSON, while the full-exchange snapshot endpoint returns an entire exchange in one JSON response served from an hourly cache.
Access to the Bulk Fundamentals API requires the Extended Fundamentals subscription plan. Details of this plan are provided upon request — please contact support@eodhistoricaldata.com. The All-in-One package on its own does not include Extended Fundamentals.
Two Endpoints, Two Jobs
Both endpoints return the same fundamentals record format for the same universe of stocks. They differ in how you select and receive the data — pick the one that matches your workflow.
| Bulk endpoint | Full-exchange snapshot | |
|---|---|---|
| Path | /api/bulk-fundamentals/{EXCHANGE_CODE} | /api/v2/bulk-fundamentals/{EXCHANGE_CODE} |
| Scope | Whole exchange, a paginated slice, or a chosen list of symbols | Whole exchange only |
| Pagination (offset, limit) | Yes, up to 500 symbols per request | No — the full exchange is returned at once |
| Symbol selection (symbols) | Yes | No |
| Format | JSON or CSV | JSON only |
| Data source | Live | Hourly cache snapshot |
| When data is not ready | Always available | Returns 503 with a Retry-After header while the snapshot rebuilds |
| Best for | Selective pulls, pagination, CSV export | Pulling an entire exchange in one fast call |
| Cost | 100 API calls (or 100 + number of symbols) | 5,000 API calls |
API Call Cost
- A regular single-ticker Fundamentals request costs 10 API calls (for reference).
- Bulk endpoint — 100 API calls per request when no symbols are specified.
- Bulk endpoint with the symbols parameter — 100 + the number of symbols. For example, a request for 3 symbols costs 103 API calls.
- Full-exchange snapshot endpoint — 5,000 API calls per request. A single call delivers the entire exchange, replacing the many paginated requests the bulk endpoint would need.
Coverage and Limits
- Stocks only. Common stocks are covered; ETFs and mutual funds are not supported.
- Exchange code in the path. Use the general US code or address these US exchanges separately: NASDAQ, NYSE (or NYSE MKT), BATS, and AMEX. All non-US exchanges are supported as usual — see the full list of supported exchanges and codes here.
- Maximum 500 symbols per request on the bulk endpoint. Page through larger exchanges with offset and limit. The snapshot endpoint has no such limit — it returns the whole exchange in one response.
- Reduced field set. Each bulk record carries fewer fields than a single-ticker Fundamentals response, and historical data is limited to the last 4 quarters and last 4 years.
Bulk Endpoint
GET /api/bulk-fundamentals/{EXCHANGE_CODE} returns fundamentals for the exchange named in the path. Use offset and limit to page through the exchange up to 500 symbols at a time, pass symbols to fetch a specific list, and choose JSON or CSV with fmt. This endpoint reads live data.
Path Parameter
EXCHANGE_CODE
string
required
Query Parameters
api_token
string
required
fmt
string
optional
offset
integer
optional
limit
integer
optional
symbols
string
optional
version
string
optional
Request Examples
All examples below use version 1.2 for the full current-template output. Fundamentals for an entire exchange, in JSON:
https://eodhd.com/api/bulk-fundamentals/NASDAQ?api_token={YOUR_API_TOKEN}&fmt=json&version=1.2
curl --location "https://eodhd.com/api/bulk-fundamentals/NASDAQ?api_token={YOUR_API_TOKEN}&fmt=json&version=1.2"
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://eodhd.com/api/bulk-fundamentals/NASDAQ?api_token={YOUR_API_TOKEN}&fmt=json&version=1.2',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'GET',
));
$data = curl_exec($curl);
curl_close($curl);
try {
$data = json_decode($data, true, 512, JSON_THROW_ON_ERROR);
var_dump($data);
} catch (Exception $e) {
echo 'Error. '.$e->getMessage();
}
import requests
url = f'https://eodhd.com/api/bulk-fundamentals/NASDAQ?api_token={YOUR_API_TOKEN}&fmt=json&version=1.2'
data = requests.get(url).json()
print(data)
library(httr)
library(jsonlite)
url <- 'https://eodhd.com/api/bulk-fundamentals/NASDAQ?api_token={YOUR_API_TOKEN}&fmt=json&version=1.2'
response <- GET(url)
if (http_type(response) == "application/json") {
content <- content(response, "text", encoding = "UTF-8")
cat(content)
} else {
cat("Error while receiving data\n")
}
Try it now (it's free)!
How to use it (YouTube)
Pagination — retrieve 200 symbols starting from symbol #1000:
https://eodhd.com/api/bulk-fundamentals/NASDAQ?offset=1000&limit=200&api_token={YOUR_API_TOKEN}&fmt=json&version=1.2
curl --location "https://eodhd.com/api/bulk-fundamentals/NASDAQ?offset=1000&limit=200&api_token={YOUR_API_TOKEN}&fmt=json&version=1.2"
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://eodhd.com/api/bulk-fundamentals/NASDAQ?offset=1000&limit=200&api_token={YOUR_API_TOKEN}&fmt=json&version=1.2',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'GET',
));
$data = curl_exec($curl);
curl_close($curl);
try {
$data = json_decode($data, true, 512, JSON_THROW_ON_ERROR);
var_dump($data);
} catch (Exception $e) {
echo 'Error. '.$e->getMessage();
}
import requests
url = f'https://eodhd.com/api/bulk-fundamentals/NASDAQ?offset=1000&limit=200&api_token={YOUR_API_TOKEN}&fmt=json&version=1.2'
data = requests.get(url).json()
print(data)
library(httr)
library(jsonlite)
url <- 'https://eodhd.com/api/bulk-fundamentals/NASDAQ?offset=1000&limit=200&api_token={YOUR_API_TOKEN}&fmt=json&version=1.2'
response <- GET(url)
if (http_type(response) == "application/json") {
content <- content(response, "text", encoding = "UTF-8")
cat(content)
} else {
cat("Error while receiving data\n")
}
Try it now (it's free)!
How to use it (YouTube)
A specific list of symbols (the exchange code in the path is ignored):
https://eodhd.com/api/bulk-fundamentals/NASDAQ?&symbols=AAPL.US,MSFT.US&api_token={YOUR_API_TOKEN}&fmt=json&version=1.2
curl --location "https://eodhd.com/api/bulk-fundamentals/NASDAQ?&symbols=AAPL.US,MSFT.US&api_token={YOUR_API_TOKEN}&fmt=json&version=1.2"
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://eodhd.com/api/bulk-fundamentals/NASDAQ?&symbols=AAPL.US,MSFT.US&api_token={YOUR_API_TOKEN}&fmt=json&version=1.2',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'GET',
));
$data = curl_exec($curl);
curl_close($curl);
try {
$data = json_decode($data, true, 512, JSON_THROW_ON_ERROR);
var_dump($data);
} catch (Exception $e) {
echo 'Error. '.$e->getMessage();
}
import requests
url = f'https://eodhd.com/api/bulk-fundamentals/NASDAQ?&symbols=AAPL.US,MSFT.US&api_token={YOUR_API_TOKEN}&fmt=json&version=1.2'
data = requests.get(url).json()
print(data)
library(httr)
library(jsonlite)
url <- 'https://eodhd.com/api/bulk-fundamentals/NASDAQ?&symbols=AAPL.US,MSFT.US&api_token={YOUR_API_TOKEN}&fmt=json&version=1.2'
response <- GET(url)
if (http_type(response) == "application/json") {
content <- content(response, "text", encoding = "UTF-8")
cat(content)
} else {
cat("Error while receiving data\n")
}
Try it now (it's free)!
How to use it (YouTube)
Full-Exchange Snapshot Endpoint
GET /api/v2/bulk-fundamentals/{EXCHANGE_CODE} returns every symbol on the exchange in one JSON response, served from a snapshot that is rebuilt hourly in the background. It takes no offset, limit, or symbols parameters — those are ignored — and always returns the full exchange. This is the fastest way to pull a complete exchange in a single call and avoids the many paginated requests the bulk endpoint would need.
Path Parameter
EXCHANGE_CODE
string
required
Query Parameters
api_token
string
required
When the hourly snapshot is being rebuilt, the endpoint returns 503 Service Unavailable with a Retry-After header giving the number of seconds to wait. Back off for that interval and retry, rather than treating it as a hard error. The response can be large — stream it instead of buffering the whole payload in memory.
Request Example
https://eodhd.com/api/v2/bulk-fundamentals/NASDAQ?api_token={YOUR_API_TOKEN}
curl --location "https://eodhd.com/api/v2/bulk-fundamentals/NASDAQ?api_token={YOUR_API_TOKEN}&fmt=json"
$curl = curl_init();
curl_setopt_array($curl, array(
CURLOPT_URL => 'https://eodhd.com/api/v2/bulk-fundamentals/NASDAQ?api_token={YOUR_API_TOKEN}&fmt=json',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => '',
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 0,
CURLOPT_FOLLOWLOCATION => true,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => 'GET',
));
$data = curl_exec($curl);
curl_close($curl);
try {
$data = json_decode($data, true, 512, JSON_THROW_ON_ERROR);
var_dump($data);
} catch (Exception $e) {
echo 'Error. '.$e->getMessage();
}
import requests
url = f'https://eodhd.com/api/v2/bulk-fundamentals/NASDAQ?api_token={YOUR_API_TOKEN}&fmt=json'
data = requests.get(url).json()
print(data)
library(httr)
library(jsonlite)
url <- 'https://eodhd.com/api/v2/bulk-fundamentals/NASDAQ?api_token={YOUR_API_TOKEN}&fmt=json'
response <- GET(url)
if (http_type(response) == "application/json") {
content <- content(response, "text", encoding = "UTF-8")
cat(content)
} else {
cat("Error while receiving data\n")
}
Try it now (it's free)!
How to use it (YouTube)
Output
Both endpoints return a JSON array, one object per company. Each object groups fundamentals into the blocks below. The set mirrors the single-ticker Fundamentals API with fewer fields, and the Earnings and Financials blocks are capped at the last 4 quarters and last 4 years. Here is an example CSV output for Apple Inc. (AAPL.US) and Microsoft Corporation (MSFT.US).
Use version 1.2 on the bulk endpoint for the full current-template output (Earnings Trends included) — it is a superset of the older format and matches what the snapshot endpoint returns. Version 1.2 is JSON only, and the 4 quarters / 4 years history limit still applies. Note on version 1.0: when version is omitted the API falls back to the original 1.0 format, built on an earlier fundamentals template — it is leaner and omits some blocks such as Earnings Trends, and is kept only for backward compatibility with existing integrations.
[
{
"General": { "Code": "AAPL", "Type": "Common Stock", "Name": "Apple Inc.", "Exchange": "NASDAQ", "ISIN": "US0378331005", "Sector": "Technology", "...": "..." },
"Highlights": { "MarketCapitalization": 3200000000000, "PERatio": 32.1, "DividendYield": 0.0045, "EarningsShare": 6.61, "...": "..." },
"Valuation": { "TrailingPE": 32.1, "ForwardPE": 28.4, "PriceSalesTTM": 8.2, "PriceBookMRQ": 51.3, "...": "..." },
"SharesStats": { "SharesOutstanding": 14900000000, "SharesFloat": 14880000000, "...": "..." },
"Technicals": { "Beta": 1.24, "52WeekHigh": 260.1, "52WeekLow": 164.1, "50DayMA": 228.4, "...": "..." },
"SplitsDividends":{ "ForwardAnnualDividendRate": 1.04, "PayoutRatio": 0.15, "ExDividendDate": "2026-05-12", "...": "..." },
"AnalystRatings": { "Rating": 4.2, "TargetPrice": 275.0, "Buy": 21, "Hold": 8, "...": "..." },
"Earnings": { "Trend": { "...": "..." }, "Last_0": { "...": "..." }, "Last_1": { "...": "..." } },
"Financials": { "Balance_Sheet": { "...": "..." }, "Cash_Flow": { "...": "..." }, "Income_Statement": { "...": "..." } }
}
]
| Block | Contents |
|---|---|
| General | Identification and classification: Code, Name, Exchange, currency, country, ISIN, CUSIP, CIK, sector and industry, GIC classification, IPO date, delisting flag, description |
| Highlights | Headline metrics: market capitalization, EBITDA, PE and PEG ratios, book value, dividend share and yield, EPS and EPS estimates, margins, and returns |
| Valuation | Valuation multiples: trailing and forward PE, price-to-sales, price-to-book, enterprise value and its ratios |
| SharesStats | Share statistics: shares outstanding and float, insider and institutional ownership, short interest |
| Technicals | Technical figures: beta, 52-week high and low, 50- and 200-day moving averages, short-interest figures |
| SplitsDividends | Forward dividend rate and yield, payout ratio, dividend and ex-dividend dates, last split factor and date |
| AnalystRatings | Consensus rating, target price, and the count of strong buy, buy, hold, sell, and strong sell ratings |
| Earnings | Earnings trend plus the last 4 reported quarters (Last_0 to Last_3) |
| Financials | Balance sheet, cash flow, and income statement, limited to the last 4 quarters and last 4 years |
Response Codes
| Code | Meaning |
|---|---|
| 200 | Success; fundamentals returned |
| 401 | Unauthorized; missing or invalid API token |
| 403 | Plan does not include Extended Fundamentals access |
| 422 | Invalid query parameters |
| 503 | Snapshot endpoint only; the hourly snapshot is being rebuilt. Wait the number of seconds in the Retry-After header and retry |