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 |
403 | forbidden | revoked/rotated key, wrong host, lapsed plan, or an edge/proxy block — not a tier restriction |
404 | not found | calling a path that doesn't exist — e.g. |
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.
there's no /probabilities endpoint (and other 404s)
a 404 means the route you called doesn't exist. the most common version of this is guessing a metric-named path like /probabilities, /winrate, or /stats. none of those exist — the edgeful API isn't organized by metric name.
every call is a report-slug call: you request a specific report by its slug — like gap-fill-standard or opening-range-breakout-standard — against the base URL https://api.edgeful.com. API v1 is served at the root of that host — there's no /v1 segment in the path.
so if you're getting a 404, check the report slug against the catalog rather than guessing an endpoint name. the full, current list of valid report slugs lives in the docs at edgeful.com/docs (report catalog under api-reference/reports). slugs are case-sensitive and use dashes.
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.
403 forbidden — "I can no longer pull reports"
a 403 isn't part of the edgeful API's normal flow — the API is user-scoped and doesn't issue tier-based 403s (see about tier access below). so if a request that used to work suddenly returns 403 and you can no longer pull reports, the cause is almost always one of these — not a permission change on your reports:
your key was rotated or revoked. if you regenerated or deleted the key in the API dashboard, the old value stops working immediately. some HTTP clients surface that as a 403 rather than a 401. generate a fresh key and update your code with the new value.
you're hitting the wrong host. the API lives at
https://api.edgeful.com. requests sent towww.edgeful.comor the docs site can come back 403 from the web layer, not from the API.an edge/proxy or firewall is blocking the call. a corporate network, VPN, or security proxy can return 403 before the request ever reaches us. test the same request from a different network, or in the docs' "try it" panel — if it works there, the block is on your side.
your subscription lapsed. if a payment failed and your plan moved to an unpaid state, API access pauses with it. check manage account → payment details and restore the card if needed.
if the key is current, you're hitting api.edgeful.com, your plan is active, and it still 403s, send support the exact request URL (mask your key), the full response body, and a timestamp — that's a case we want to see.
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, so the API itself doesn't issue a tier-based 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. if you are seeing a 403, it isn't coming from tier authorization — see 403 forbidden above for what actually causes it.
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, and does it exist in the docs catalog? a mistyped or invented slug returns 404 or 422, not data.
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 else. v1 is served at the root of that host — there's no/v1in the path.check 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.