Programmatic access to StashGamma end-of-day stock data — pick a date range, get back real OHLCV bars for any U.S.-listed symbol, going back 15 years.
The Developer API has one endpoint: daily end-of-day OHLCV bars for a symbol, over a date range you choose. All requests are read-only (GET) and require an API key. Base URL:
https://www.stashgamma.com/api/dataapi/v1
Pass your API key via either header — both are accepted, use whichever your HTTP client/library makes more convenient:
X-Api-Key: sg_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # or Authorization: Bearer sg_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Get a key from Profile → Developer API — the Free tier is instant and self-serve, no payment required.*
* No credit card, ever — subject to the fair-use throttling limits below (300 req/hour · 800/day · 4,000/week). Keys that repeatedly exceed a window may see additional cooldown beyond the standard Retry-After.
| Plan | Price | Per hour | Per day | Per week |
|---|---|---|---|---|
| Free | $0 | 300 | 800 | 4000 |
Every response (success or error) includes rate-limit headers so you can self-throttle without guessing:
X-RateLimit-Plan: free X-RateLimit-Limit-Hour: 300 X-RateLimit-Remaining-Hour: 297 X-RateLimit-Limit-Day: 800 X-RateLimit-Remaining-Day: 790 X-RateLimit-Limit-Week: 4000 X-RateLimit-Remaining-Week: 3950
A 429 also includes a standard Retry-After header (seconds until the exceeded window resets).
Daily OHLCV bars for one symbol, optionally sliced to a date range.
| Param | Type | Required | Notes |
|---|---|---|---|
| symbol | path | yes | e.g. QQQ, case-insensitive |
| from | query | no | YYYY-MM-DD, default = 30 days before to |
| to | query | no | YYYY-MM-DD, default = today |
Example request
curl -H "X-Api-Key: YOUR_API_KEY" \ "https://www.stashgamma.com/api/dataapi/v1/eod/QQQ?from=2026-07-01&to=2026-08-01"
Example response — 200 OK
{
"symbol": "QQQ",
"from": "2026-07-01",
"to": "2026-08-01",
"count": 23,
"bars": [
{ "date": "2026-07-01", "open": 611.2, "high": 614.8, "low": 609.5, "close": 613.1, "volume": 28451200 },
{ "date": "2026-07-02", "open": 613.4, "high": 615.0, "low": 611.9, "close": 614.2, "volume": 24310500 }
]
}Working, copy-pasteable examples for curl, Python, JavaScript, Node.js, Java, Go, Excel, and a Jupyter notebook are in the step-by-step quickstart guide. Downloadable source for all of them (plus MCP client examples):
| Language | File |
|---|---|
| Python | eod_quickstart.py |
| Node.js | eod-quickstart.mjs |
| Java | StashGammaEodExample.java |
| Go | main.go |
| Jupyter / pandas | stashgamma_eod_quickstart.ipynb |
| MCP (Python & Node clients) | mcp/ |
Every example reads the key from an environment variable (STASHGAMMA_API_KEY) and demonstrates backing off on a 429 using the Retry-After header — copy that pattern into your own client.
If you're wiring StashGamma data into Claude or another MCP-capable agent instead of calling the REST endpoint directly, point it at the Streamable HTTP MCP endpoint below. Same API key, same rate-limit bucket as /v1/eod/{symbol} — a tool call and a REST call against the same key draw from the same hour/day/week quota.
https://www.stashgamma.com/api/dataapi/mcp
Auth is the same X-Api-Key / Authorization: Bearer header, sent alongside the JSON-RPC POST body — most MCP client configs let you set custom headers per server.
Some hosted AI assistants only give you a box for a server URL, with no way to add a header. For those, put the key in the URL instead — either form works, and both are treated exactly like the header:
https://www.stashgamma.com/api/dataapi/mcp/YOUR_API_KEY https://www.stashgamma.com/api/dataapi/mcp?key=YOUR_API_KEY
A URL with a key in it is a secret — it can end up in that assistant's saved settings and logs. If one leaks, rotate the key from Profile → Developer API and the old URL stops working immediately. When a header is also sent, the header wins.
Three read-only tools are exposed:
| Tool | Arguments | Returns |
|---|---|---|
| get_eod_data | symbol (required), from/to (optional, YYYY-MM-DD) | Same OHLCV bar shape as the REST endpoint |
| get_latest_quote | symbol (required) | Most recent daily bar plus change vs the previous close |
| get_api_usage | none | Plan, used/remaining requests per hour/day/week — does not count against quota |
Stateless — every call is a single JSON response (no SSE stream, no session to keep alive). Rate-limit/auth errors come back as a tool result with isError: true rather than an HTTP error, so your agent can see and react to the reason (e.g. "retry in Ns") directly.
Step-by-step setup, ready-to-drop config files, and code samples for each client:
url + headers entry into your MCP server config.type: "mcp" tool.get_eod_data directly via the official Python or Node.js MCP SDK.Full walkthrough for each: Connect via MCP.
| Status | When | Example body |
|---|---|---|
| 400 | Missing symbol in path, or `from`/`to` malformed/inverted | {"error":"\"from\" must be on or before \"to\"","success":false} |
| 401 | Missing API key (no X-Api-Key / Authorization header) | {"error":"Missing API key. Pass it via the X-Api-Key header or Authorization: Bearer <key>.","success":false} |
| 401 | Malformed, unknown, expired, suspended, or revoked key | {"error":"This API key has expired — resubscribe to get a new one","success":false} |
| 404 | No EOD data for that symbol | {"error":"No EOD data for symbol ZZZZ","success":false} |
| 429 | Hour/day/week rate limit exceeded for your plan | {"error":"Rate limit exceeded for the hour window (101/100). Try again in 1800s.","success":false} |
Live uptime and per-endpoint health (tested daily, automatically) are on the API status page. Questions or issues: contact support.