The data layer for Robinhood
Elgon is a market-data API covering stocks, ETFs, options, crypto and prediction markets through one endpoint. Every response ships with a signed, timestamped, tamper-evident receipt — a SHA-256 commitment you can recompute yourself to confirm the payload wasn't altered in transit.
⚡ One API, many markets
Quotes, options chains, prediction contracts and instrument search — stocks, ETFs, options, and BTC/ETH crypto — over clean JSON.
🔏 Tamper-evident
Each response carries a receipt: sha256(data + ts). Recompute it locally or call the verify endpoint. No trust required.
🧪 Public demo key
Try every endpoint right now with the shared key elgon_sandbox_pub — no signup. Quotes & instruments return real (delayed) data; options & predictions are simulated and labeled as such.
"source":"live", even on the public demo key. Options and predictions are currently simulated sample data, always tagged "source":"sandbox" with an explanatory note — don't trade or report on them. See Sandbox vs live.Quickstart
Send your first request in under a minute using the public sandbox key elgon_sandbox_pub. No account needed.
curl "https://elgonrpc.xyz/api/v1/quotes?symbol=AAPL&key=elgon_sandbox_pub" # or with a bearer token curl "https://elgonrpc.xyz/api/v1/quotes?symbol=AAPL" \ -H "Authorization: Bearer elgon_sandbox_pub"
const res = await fetch( "https://elgonrpc.xyz/api/v1/quotes?symbols=AAPL,TSLA", { headers: { Authorization: "Bearer elgon_sandbox_pub" } } ); const { data, source, plan, receipt } = await res.json(); console.log(source); // "live" — real quotes (delayed, not real-time) console.log(data[0].price); // e.g. 333.74 console.log(receipt.hash); // sha256 integrity commitment
From this site you can also call the API same-origin as /api/v1/quotes?... — the hostname resolves to the same functions.
Get an API key
Mint a free key with one request — no account, no card. The key is returned once; store it immediately.
curl -X POST "https://elgonrpc.xyz/api/keys"
{
"key": "elgon_live_9f2c8a1e4d7b0c6a5e31b8d204f6a7c1",
"plan": "free",
"limit": "60 requests/min",
"note": "Store this key now — it is shown only once. Use it as Authorization: Bearer <key> or ?key=<key>."
}
You can also mint and manage keys from the dashboard, or just prototype with the shared public key elgon_sandbox_pub — no signup at all.
Base URL
All endpoints live under a single versioned base URL. Regional routing is handled for you; you always call the same host.
| Purpose | URL |
|---|---|
| REST API base | https://elgonrpc.xyz/api/v1 |
| Receipt verifier | https://elgonrpc.xyz/api/v1/verify |
| Health check | https://elgonrpc.xyz/api/v1/ping |
All endpoints are GET, respond with JSON, send CORS access-control-allow-origin: *, and answer OPTIONS preflight — so they're callable directly from the browser.
Authentication
Every request is authenticated with an API key. Pass it any of three ways — pick whichever suits your client:
Authorization: Bearer $ELGON_API_KEY
x-api-key: $ELGON_API_KEY
?key=$ELGON_API_KEY
Key types
| Key | What it is |
|---|---|
elgon_sandbox_pub | Public demo key. Always valid, free-tier limits. Safe to embed in client-side demos; used by the homepage "try it" widget. Data behavior is the same as any key: quotes/instruments real (delayed, "source":"live"), options/predictions simulated ("source":"sandbox"). |
elgon_live_<32 hex> | Live keys — the literal prefix elgon_live_ followed by 32 hex characters. Minted via POST /api/keys or from your dashboard, scoped to a plan, validated server-side. Keep these secret and server-side. |
elgon_sandbox_pub key is designed to be public; live keys are not. If the key backend is unreachable, live keys fail closed with 503 backend_unavailable — the sandbox key keeps working since it needs no database. A missing or invalid key returns 401 unauthorized.Sandbox vs live
The seam between real and simulated data runs per endpoint, not per key — the same behavior applies whether you use elgon_sandbox_pub or a live key:
| Endpoint | Data | source tag |
|---|---|---|
| Quotes, Instruments | Real market data. Delayed, not real-time — don't use it as a live trading feed. | "live" |
| Options, Predictions | Simulated sample data — deterministic values seeded from the symbol, stable and plausible across calls, but not real market prices. | "sandbox" |
Every simulated payload also carries an explicit note field: "Sandbox data — deterministic sample values seeded from the symbol, not real-time market prices. Do not trade on these."
source field before you use a number. When it says "sandbox", the data is illustrative sample data — not a market quote. When it says "live", the data is real but delayed. Elgon never presents simulated numbers as real prices, and never presents delayed quotes as real-time.Quotes
Quotes for one or more symbols across stocks, ETFs and crypto. This is real market data, but delayed — not real-time. Responses are tagged "source":"live" even on the public demo key.
| Param | Type | Description |
|---|---|---|
symbol | string | A single symbol, e.g. AAPL. |
symbols | string | Comma-separated list, e.g. AAPL,TSLA,SPY. Use instead of symbol for batches. Crypto uses the -USD suffix, e.g. BTC-USD. |
GET /api/v1/quotes?symbols=AAPL,BTC-USD&key=elgon_sandbox_pub
{
"data": [
{
"symbol": "AAPL",
"name": "Apple Inc.",
"price": 333.74,
"change": 0.48,
"changePct": 0.14,
"bid": 333.71,
"ask": 333.77,
"volume": 63407059,
"currency": "USD",
"assetClass": "stock",
"asOf": "2026-07-19T21:25:16.131Z"
},
{
"symbol": "BTC-USD",
"name": "Bitcoin USD",
"price": 64422.08,
"change": -372.17,
"changePct": -0.57,
"bid": 64415.64,
"ask": 64428.52,
"volume": 14257716224,
"currency": "USD",
"assetClass": "stock",
"asOf": "2026-07-19T21:25:16.081Z"
}
],
"source": "live",
"plan": "free",
"receipt": {
"alg": "sha256",
"hash": "6effc13adb9bba63…6371bc",
"ts": "2026-07-19T21:25:16.131Z",
"endpoint": "/api/v1/quotes",
"verifyUrl": "https://elgonrpc.xyz/api/v1/verify"
}
}
changePct is rounded to 2 decimals. asOf is when Elgon served the quote — it is not proof of real-time freshness: the underlying price is delayed relative to the exchange feed.
Options
An options chain and available expirations for an underlying symbol. Always simulated: values are deterministic samples seeded from the symbol, tagged "source":"sandbox" with a do-not-trade note. Expirations are the next four monthly cycles.
| Param | Type | Description |
|---|---|---|
symbol | string | Underlying symbol, e.g. AAPL. Required. |
GET /api/v1/options?symbol=AAPL&key=elgon_sandbox_pub
{
"symbol": "AAPL",
"underlying": 227.5,
"expirations": ["2026-08-21", "2026-09-18", "2026-10-16", "2026-11-20"],
"chain": [
{ "strike": 220, "type": "call", "bid": 15.67, "ask": 16.63, "iv": 0.67, "oi": 8236, "expiry": "2026-08-21" },
{ "strike": 220, "type": "put", "bid": 3.38, "ask": 3.58, "iv": 0.49, "oi": 15217, "expiry": "2026-08-21" },
{ "strike": 225, "type": "call", "bid": 7.26, "ask": 7.70, "iv": 0.57, "oi": 19169, "expiry": "2026-08-21" }
],
"source": "sandbox",
"plan": "free",
"receipt": {
"alg": "sha256",
"hash": "bc07344362ba13aa…acd180b",
"ts": "2026-07-19T21:25:21.412Z",
"endpoint": "/api/v1/options",
"verifyUrl": "https://elgonrpc.xyz/api/v1/verify"
},
"note": "Sandbox data — deterministic sample values seeded from the symbol, not real-time market prices. Do not trade on these."
}
Note the simulated underlying price will not match the real delayed price from /quotes — the two endpoints draw from different sources by design.
Predictions
Event contracts with yes/no pricing. Always simulated: a small fixed set of sample contracts, tagged "source":"sandbox" with a do-not-trade note — not a feed from any real prediction market.
| Param | Type | Description |
|---|---|---|
q | string | Optional. Filter contracts by keyword, e.g. fed. Omit to list active contracts. |
GET /api/v1/predictions?q=fed&key=elgon_sandbox_pub
{
"data": [
{
"id": "fed-cut-sep",
"question": "Fed cuts rates in September?",
"category": "macro",
"yesPrice": 0.62,
"noPrice": 0.38,
"volume": 1305720,
"closesAt": "2026-09-17T18:00:00Z"
}
],
"source": "sandbox",
"plan": "free",
"receipt": {
"alg": "sha256",
"hash": "6fb36571488bbd33…7bd6e6",
"ts": "2026-07-19T21:25:22.397Z",
"endpoint": "/api/v1/predictions",
"verifyUrl": "https://elgonrpc.xyz/api/v1/verify"
},
"note": "Sandbox data — deterministic sample values seeded from the symbol, not real-time market prices. Do not trade on these."
}
Instruments
Search the instrument catalog — resolve a name or partial ticker to real listed symbols across exchanges. This is real reference data, tagged "source":"live".
| Param | Type | Description |
|---|---|---|
q | string | Search query, e.g. apple. Required. |
GET /api/v1/instruments?q=apple&key=elgon_sandbox_pub
{
"data": [
{ "symbol": "AAPL", "name": "Apple Inc.", "type": "equity", "exchange": "NASDAQ", "assetClass": "stock" },
{ "symbol": "AAPL.SW","name": "APPLE INC", "type": "equity", "exchange": "Swiss", "assetClass": "stock" },
{ "symbol": "APLE", "name": "Apple Hospitality REIT, Inc.", "type": "equity", "exchange": "NYSE", "assetClass": "stock" }
],
"source": "live",
"plan": "free",
"receipt": {
"alg": "sha256",
"hash": "560c86c51a9105d1…4df7b",
"ts": "2026-07-19T21:25:17.092Z",
"endpoint": "/api/v1/instruments",
"verifyUrl": "https://elgonrpc.xyz/api/v1/verify"
}
}
Verify
Recompute a receipt server-side. Pass the receipt's hash and ts plus the canonical JSON of the response data you received; the endpoint recomputes the hash and tells you whether it matches.
| Param | Type | Description |
|---|---|---|
hash | string | The receipt.hash value to check. |
ts | string | The receipt.ts value (ISO 8601). |
payload | string | URL-encoded canonical JSON of the data field you received. |
GET /api/v1/verify?hash=9f2c8a1e…e07b&ts=2026-07-15T15:32:04.112Z&payload=%5B%7B...%7D%5D
{ "valid": true }
This is the same computation described in Verifying a receipt — use it when you'd rather not implement canonicalization yourself.
Ping
A dependency-free health check. Returns 200 with a small JSON body — handy for uptime probes.
GET /api/v1/ping
{ "ok": true, "service": "elgon-api", "runtime": "node", "version": "v24.18.0" }
No API key is required for ping.
Signed receipts
Every data response carries a receipt object. It is a tamper-evident integrity commitment, not a marketing badge: a SHA-256 hash over the exact payload you received plus the timestamp it was served at.
"receipt": {
"alg": "sha256",
"hash": "<hex>", // sha256( canonicalJSON(data) + "|" + ts )
"ts": "2026-07-15T15:32:04.112Z", // when it was served (ISO 8601)
"endpoint": "/api/v1/quotes",
"verifyUrl": "https://elgonrpc.xyz/api/v1/verify"
}
Because the hash binds the data and the time together, anyone can confirm — without contacting Elgon again — that the payload they hold is byte-for-byte what was served at ts. If a proxy, cache or man-in-the-middle alters a single digit, the recomputed hash won't match.
This is an honest integrity check over the served bytes. It proves the payload is intact and consistent with its timestamp; it is not a claim about market accuracy — for that, read the source field.
Verifying a receipt
Two ways to verify — pick one.
1. Call the verify endpoint
Send the hash, ts and the canonical data back to /api/v1/verify and read { "valid": true }.
2. Recompute it locally
Canonicalize the data field (recursively key-sorted JSON), join it to the timestamp with a |, and SHA-256 the result. Compare against receipt.hash.
import { createHash } from "node:crypto"; // stable, recursively key-sorted JSON function canonical(v){ if (Array.isArray(v)) return "[" + v.map(canonical).join(",") + "]"; if (v && typeof v === "object") return "{" + Object.keys(v).sort() .map(k => JSON.stringify(k) + ":" + canonical(v[k])).join(",") + "}"; return JSON.stringify(v); } function verifyReceipt(data, receipt){ const h = createHash("sha256") .update(canonical(data) + "|" + receipt.ts) .digest("hex"); return h === receipt.hash; } // usage const { data, receipt } = await res.json(); console.log(verifyReceipt(data, receipt)); // true → payload intact
If your client can't reproduce the exact canonical form, use the verify endpoint instead — it runs the same computation server-side.
Rate limits & plans
Limits are per-minute. On every successful response Elgon returns x-ratelimit-limit and x-ratelimit-remaining headers. Exceeding the limit returns 429 with { "error": { "code": "rate_limited" } }.
| Plan / key | Requests / min | Notes |
|---|---|---|
elgon_sandbox_pub | 60 (soft) | Best-effort. The public demo degrades rather than hard-failing. |
| Free | 60 | Default for issued live keys. |
| Growth | 600 | Higher throughput for production apps. |
| Enterprise | Custom | Negotiated limits & priority. |
The active plan is echoed back in the plan field on data responses.
Errors
Errors use a consistent shape: { "error": { "code": "...", "message": "..." } } with a matching HTTP status.
| Status | Code | Meaning |
|---|---|---|
401 | unauthorized | Missing or invalid API key. |
429 | rate_limited | Per-minute limit exceeded. Check x-ratelimit-* headers. |
503 | backend_unavailable | Key-validation backend unreachable (live keys fail closed). The sandbox key still works. |
FAQ
Can I use Elgon from the browser?
Yes. Endpoints send permissive CORS headers and handle preflight, and elgon_sandbox_pub is safe to expose client-side. Keep live keys on your server.
Which data is real and which is simulated?
Quotes and instruments are real — actual market data, tagged "source":"live", but delayed, not real-time. Options and predictions are simulated — deterministic sample data, tagged "source":"sandbox" with an explanatory do-not-trade note. This split applies on every key, including elgon_sandbox_pub.
Are quotes real-time?
No. Quotes are real market data but delayed. Don't build anything that assumes real-time freshness — for execution-grade data you need a real-time feed from a licensed vendor.
What does the receipt actually prove?
That the payload you hold is byte-for-byte what Elgon served at the receipt's timestamp. It's a SHA-256 integrity commitment you can recompute — it detects tampering in transit. It is not a statement about market accuracy; for that, read the source field.
How do I get a live key?
POST https://elgonrpc.xyz/api/keys mints a free key instantly (see Get an API key), or issue one from the dashboard. Live keys look like elgon_live_<32 hex>, carry a plan, and are validated server-side.