Authentication: the X-API-KEY header and account-level quotas
The Algoseek Datasets API authenticates every request via a single HTTP
header: X-API-KEY. There is no OAuth flow, no token-refresh
endpoint, no signed URL — you place your raw key in the header on
every request, and the server does the rest.
The header in two lines
X-API-KEY: paste-your-key-here
That is the whole authentication contract. The header name is
case-insensitive on the wire (per RFC 7230), but the documentation
spells it X-API-KEY in upper-case-with-hyphens. Match the
documentation casing in your client so log searches against either
the docs or the server logs match your code verbatim.
Three layered checks: identity, IP, entitlement
When you send a request, the server runs three checks in order.
1. Identity.
Is the value in X-API-KEY a known,
active key? If not — if it is missing, malformed, deactivated, or just
a typo — the server returns 401 Unauthorized.
2. IP whitelist.
Is the source IP of the request on the
allow-list configured for this key? If not, you get 403 Forbidden.
The allow-list is per-key and is configured out of band.
You can read your current allow-list from the identity envelope, which
the first-request chapter walks through in detail.
3. Entitlement.
Is the dataset you are asking about
included in this key's data-access rules? If not, you get
403 Forbidden with a payload like
{"detail":"The account is not authorized to access the dataset ..."}.
Note that the first two checks happen on the
edge, before the request hits the application, but the entitlement
check runs after request parsing — so a 4xx coming back may be from
either layer, and your client must read the response body to be sure
which.
The order matters for production diagnostics. A blanket retry-on-403 loop will burn your quota indefinitely if the underlying problem is an IP allow-list issue. Inspect the response body; if it mentions "dataset", it is an entitlement failure (rectifiable by changing the endpoint or your subscription); if it mentions "IP" or is empty, it is the IP allow-list (rectifiable only by talking to your account contact).
Sending the header from each language
Python (requests).
import os
import requests
API_KEY = os.environ["ALGOSEEK_API_KEY"]
BASE_URL = "https://dev-datasets-api.algoseek.com"
with requests.Session() as session:
session.headers["X-API-KEY"] = API_KEY
resp = session.get(f"{BASE_URL}/api/v1/account/my", timeout=30)
resp.raise_for_status() # raises on 4xx and 5xx
print(resp.json())
A session also pools and reuses connections, applies a default
timeout if you set one on the adapter, and lets you mount
custom transport adapters — the basis for retry/backoff
(see the ingestion chapter).
Always use a session for production code.
cURL.
curl -s -H "X-API-KEY: $ALGOSEEK_API_KEY" \
"https://dev-datasets-api.algoseek.com/api/v1/account/my"
Verbose probing.
For diagnostics, run
curl -v -i ...: -v prints the full request and
response sequence including TLS handshake, and -i includes the
response headers in the body output (useful when chasing pagination,
caching, or request-id issues).
What the identity endpoint tells you
The single most useful diagnostic call is GET /api/v1/account/my. It
returns the identity that owns the key and is the basis for every other
check.
{
"identity_id": 89,
"name": "Algoseek Prod (REST API)",
"max_active_api_keys": 15,
"ip_subnets": []
}
The identity envelope is the input to every entitlement decision your
client should make. Read it once at startup, log
identity_id and name (so logs in production are
tagged with which key they came from), and write a one-line
"identity:" line in your service banner. If you ever see the wrong
account, your config is pointing at the wrong key. The fields the
deployed API actually returns are identity_id,
name, max_active_api_keys, and
ip_subnets — there is no account_name or
user_email field; do not access them.
Security note on ip_subnets. The captured
identity envelope used in this guide shows
"ip_subnets": [] on the dev key. An empty allow-list means
anyone who obtains the key can use it from anywhere
on the internet — there is no IP-level defence-in-depth. For
production keys, request a non-empty ip_subnets from
your account contact (your egress NAT range, your bastion host,
your CI runner pool's static egress IPs). At process startup,
fetch ip_subnets, resolve your current outbound IP via
a metadata service or external probe, and refuse to start if the
egress IP is not contained in the allow-list. This catches both
"my key got copied" and "my CI runner is now egressing from a
new IP" before the pipeline ever issues a data call.
Common authentication failures
| Symptom | Likely cause and fix |
|---|---|
401 on every call | Key missing, truncated, or deactivated. Compare against the value you were given (watch for trailing newlines if you piped into a file). |
403 on every call | IP not on the allow-list for this key. Check your outbound IP (curl ifconfig.me) and ask for it to be added. |
403 on some calls only | Entitlement issue. The endpoint maps to a dataset your account does not own. The body says exactly which dataset (see the errors chapter for the envelope). |
200 but the wrong account in name | Your config is pointing at someone else's key. Double-check the source. |
Mixed 200/401 on the same key | Highly unusual — usually a stale connection in a pool that picked up a deactivated key after rotation. Restart the process or drain the pool. |
Diagnostic prologue.
A useful pattern in production is a
"startup probe" that calls /status and /account/my
once before the rest of the pipeline runs, refuses to start if either
fails, and logs the identity envelope. This catches misconfigured keys
at deploy time rather than two hours into a backfill.