Skip to main content

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

The exact header the server expects.
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.

note

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).

Python: the canonical pattern. Build a session, set the header once, reuse for every call. The with block closes the underlying pool deterministically.
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: useful for ad-hoc probing and debugging. Add -i to also see the response headers (useful when chasing the AWS request-id x-amzn-RequestId, the backend x-request-id, content-disposition, or rate-limit headers).
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.

Captured response body — iam_account_my
{
"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.

warning

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

SymptomLikely cause and fix
401 on every callKey missing, truncated, or deactivated. Compare against the value you were given (watch for trailing newlines if you piped into a file).
403 on every callIP 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 onlyEntitlement 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 nameYour config is pointing at someone else's key. Double-check the source.
Mixed 200/401 on the same keyHighly 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.