if a call to the edgeful API isn't behaving the way you expect, this is the page to check first. the API returns standard HTTP status codes, and most of the errors you'll see come from a small set of common mistakes — wrong ticker format, missing header, wrong date format, hitting your tier's limits.
this article covers every error code, what it means, and the fastest way to fix it.
the error codes at a glance
status | meaning | most common cause |
200 | success | none — request worked |
401 | unauthorized | missing, malformed, or revoked API key |
422 | validation error | a parameter is missing or in the wrong format |
429 | too many requests | you hit the rate limit |
500 / 502 / 503 | server error | something's wrong on our end — retry with backoff |
the 2 you'll see most often are 422 (your request was malformed) and 429 (you're sending too many requests). 401 usually means you forgot the header or you're using a revoked key.
401 unauthorized
your key is missing, malformed, or revoked. the response body looks like this:
{"app_exception": "Unauthorized", "context": null}what to check, in order:
is the
Authorizationheader included on the request? every call needs it — no session, no cookie.is the header exactly
Authorization: Bearer <your-key>? single space between Bearer and the key, no colon after Bearer, no quotes around the key value.is the key value complete? plaintext keys are only shown once at creation — if you copied a masked version from the dashboard, that won't authenticate.
did you regenerate this key recently? if you regenerated it in the API dashboard, the old value stopped working immediately. update your code with the new value.
was the key revoked from the dashboard? a deleted key will return 401 forever — generate a new one. if the header is correct and the key is current, double-check that you're not accidentally hitting a different environment (e.g., a staging URL with a production key).
are you testing in the docs "try it" playground? the playground accepts a bare key (no
Bearerprefix) — it auto-addsBeareron the wire. if you pasteBearer sk_live_...into the playground key field, you'll get a 401 because it sendsBearer Bearer sk_live_.... paste just the key.
422 validation error
something about your request doesn't match what the endpoint expects. the response body shows you which field and why:
{ "detail": [ { "loc": ["query", "start_date"], "msg": "invalid date format", "type": "value_error.date" } ] }the loc field tells you which parameter is wrong. the most common 422 causes:
wrong ticker format for the market type
ticker format depends on market_type. mixing these up is the #1 source of 422s.
market_type | ticker format | example |
stock | plain symbol |
|
forex | 6-character pair |
|
crypto | contract pair |
|
futures | root symbol |
|
if you pass ES-MAR2024 or BTC-USD, you'll get a 422 — use the format in the table.
wrong date or time format
dates must be
YYYY-MM-DD(e.g.,2024-01-01). not01/01/2024, notJan 1 2024.times must be
HH:MM:SS(e.g.,09:30:00). not9:30 AM, not09:30.
missing required parameters on intraday endpoints
intraday endpoints (anything under intraday_calculation) require start_time, end_time, and timezone in addition to the date range. if you leave one out, you'll get a 422 telling you which parameter is missing.
session times for intraday endpoints
intraday endpoints (anything under intraday_calculation) require start_time, end_time, and timezone. these aren't free-form — they're canonical presets per market_type and session. using anything else returns 422.
the canonical presets live on the session presets docs page. full reference:
market_type | session | start_time | end_time | timezone |
forex | New York |
|
|
|
forex | London |
|
|
|
forex | Asia |
|
|
|
futures | New York |
|
|
|
futures | London |
|
|
|
futures | Asia |
|
|
|
crypto | New York |
|
|
|
crypto | London |
|
|
|
crypto | Asia |
|
|
|
stock | New York |
|
|
|
use these values exactly — the API will not normalize 09:30 to 09:30:00, for example. stock only has the New York session; the other three market types have NY / London / Asia.
daily-session presets. a few daily reports support an optional custom-session aggregation (provide start_time + end_time on a daily endpoint and it'll roll bars into your custom session). these use a separate set of preset values:
market_type | session | start_time | end_time | timezone |
forex | Daily |
|
|
|
futures | Daily |
|
|
|
crypto | Daily |
|
|
|
crypto | Crypto Daily |
|
|
|
these are not an automatic fallback for the intraday endpoints — only the daily reports that explicitly accept custom-session aggregation. when in doubt, the session presets docs mark which is which.
Asian range breakout — special case. the Asian range breakout endpoints use the Asia preset for start_time and end_time but take no timezone parameter — the range is interpreted in Asia/Tokyo automatically. they also take separate candle_start_time and candle_end_time parameters, which describe a daily candle window in America/New_York. if you treat these endpoints like the others (passing timezone), you'll get a 422.
invalid market_type value
the only valid values are forex, futures, crypto, stock. anything else (including capitalized variants like STOCK or Forex) returns a 422.
invalid report slug
report slugs are case-sensitive and use dashes, not underscores or spaces. if you pass gap_fill_standard or Gap-Fill-Standard, you'll get a 422. the correct format is gap-fill-standard. the full list of slugs lives in the API reference.
429 too many requests
you hit the rate limit. the response body:
{"detail": "API key rate limit exceeded"}the default rate limit is the same on every tier: 30 requests per 60-second window (sustained) plus a burst allowance of 5 requests per 5 seconds. limits are per key but aggregate at the account — spreading requests across multiple keys won't help.
what to do when you see a 429:
back off before retrying. an immediate retry will fail too.
use exponential backoff — wait 1s, then 2s, then 4s, etc. before each retry attempt.
if you're consistently hitting the limit, consider whether you actually need to be calling the API that often. caching responses for the duration of a trading day usually solves it.
rate limits are uniform across tiers — upgrading your plan doesn't raise them. if caching and backoff still aren't enough for your workload, reach out to support so we can review the use case.
about tier access
in API v1, keys are user-scoped — there's no per-route ACL and the API doesn't return a 403. that means there isn't a dedicated "tier-restricted" error shape. what your tier controls is which reports, tickers, and lookback window are exposed to you, not the request authorization itself.
if you call something outside your tier, the most likely outcome is a 422 (the slug or ticker isn't recognized for your access level) or empty data. there's no special tier error to handle.
the full breakdown of what each tier includes is in the rate limits + tier differences.
5xx server errors
if you get a 500, 502, or 503 — that's on us, not on you. these are rare. retry with exponential backoff. if it persists for more than a few minutes, or you suspect a wider outage (multiple endpoints down at once), ping support directly with the timestamp and the last few request URLs you tried so we can correlate against backend logs.
{"detail": "internal server error"}
troubleshooting flow
if you're stuck and don't have a clear error code to work from, work through this in order:
does the request work in the docs' "try it" panel? if yes, the issue is in your code. if no, the request itself is malformed.
is the
Authorizationheader present and correctly formatted?are all required parameters present? check
start_date,end_date, and for intraday endpoints, alsostart_time,end_time,timezone.is the ticker formatted correctly for the
market_type?is the report slug spelled correctly with dashes?
are the dates within your tier's lookback window? essentials caps at 6 months, pro at 1 year, all-access at 8 years.
is the report or ticker available in your tier? see rate limits and tier differences for the full breakdown of what each tier unlocks.
still stuck
a few last things to check:
the API base URL is
https://api.edgeful.com— make sure you're not pointing atwww.edgeful.comor anything elsecheck the docs at https://www.edgeful.com/docs for the latest endpoint catalog and parameter requirements
if your IDE or HTTP client is encoding query parameters unexpectedly (e.g., turning
:into%3A), the API will usually handle it — but it's worth testing the raw URL in curl to rule it out.deeper reference: the authentication docs cover header format, key format, and the exact error response shapes; the session presets docs cover every valid intraday session combo.
if none of that resolves it, reach out to support with the exact request URL (mask your key) and the full response body. we'll dig in.