statshawk
Guides

Production checklist

Before you ship, the ten things that bite you in production.

Before you flip the switch

These are the ten failure modes we've seen real builders hit between dev and prod. Run through the list before pointing real traffic at your integration.

01. Rotate test keys out

sk_test_… keys authenticate, meter, and rate-limit exactly like live keys: the prefix exists so you can separate sandbox traffic from production traffic in your own logs and rotate the two independently. If anything in your prod path still references a test key, your production usage lands on the key you'll casually revoke during the next experiment. Grep your secrets manager and CI config.

quick grep
git grep -n "sk_test_"

02. Set a real User-Agent

Identify yourself so we can email you before deprecating something you depend on, and so support requests pull faster traces.

curl -H "User-Agent: yourapp/1.4 (you@yourdomain.com)" ...

03. Persist meta.request_id

Capture meta.request_id in your logs for every Statshawk call. When something goes wrong you'll save a 30-minute back-and-forth: paste the IDs and we pull the traces directly.

04. Retry 5xx with back-off; branch 429 on the error code

502/503 are transient: start at 1 second, double up to a 30-second cap, give up after 3–5 attempts. A 429 carries one of two codes and they need different handling: RATE_LIMIT_EXCEEDED means you outpaced your plan's requests-per-second ceiling: honor the Retry-After header (whole seconds) and continue. QUOTA_EXCEEDED means the monthly unit cap: retrying won't help; the X-Account-Quota-Reset header carries the period-end timestamp (RFC3339) it resets at.

05. Watch both header families

X-RateLimit-Remaining is your per-second budget: pace parallel work so it never hits zero (a burst above your plan's RPS throttles the excess immediately). X-Account-Quota-Remaining is your monthly unit budget: implement back-pressure or an upgrade prompt once it drops below 10% of X-Account-Quota-Limit. Watching both is a thousand times better than getting throttled.

06. Don't retry deterministic errors

A 400, 401, 403, or 404 will return the same result on retry, and so will 501 NOT_SUPPORTED (a capability gap, not an outage). Surface them to the caller; don't loop.

07. Pin to meta.version

We don't bump versions casually, but every breaking change does bump unless the changelog records an exception. Documented exceptions: the 2026-07-24 pre-GA analysis-surface change, and the 2026-09-11 quota hard-stop (paid self-serve metered routes now return 429 QUOTA_EXCEEDED at the cap under /v1). If you key on response shape, log meta.version and watch the changelog for no-bump contract notes.

08. Use feature detection

Before assuming a competition exposes every stat phase or measure, call /v1/competitions/{comp}/capabilities once and cache the result for an hour. A 501 NOT_SUPPORTED in production is a poor look when the detection call is two lines. And if you do hit one, its error body carries machine-readable league and capability fields you can key a fallback off.

09. Cache budgets, not responses

We cache responses on our side. Caching them on yours adds a TTL stale-set you'll have to debug during a live game. Trust meta.cache instead: HIT is a fresh cached copy, and STALE means a background refresh is already running, so re-requesting shortly gets the fresh value.

10. Plan for quota exhaustion

429 QUOTA_EXCEEDED is a hard stop on every metered route for Free through Growth until the period resets (the X-Account-Quota-Reset header carries the reset timestamp) or you upgrade. There are no overage charges. Wire upgrade-or-degrade logic into your code path before launch: degrading gracefully to "tonight's lineups unavailable" beats a 500.

See also

On this page