Skip to main content

Migration Guide: v1 → v2

:::info Who is this page for? Existing v1 users — you call URLs like /{apikey}/live/user/... today.

New here? You don't need this page. Start with Get your key and Make your first request, then use the API Reference. :::

:::warning v1 is deprecated v1 still works, as a compatibility layer on top of the v2 services. Every v1 route is flagged as deprecated in the v1 Swagger (/v1/swagger) and will be removed in a future release. Migrate when you can, one endpoint at a time. :::

What changes for you​

#Whatv1v2
1Errorssuccess: 1 / error bodyReal HTTP status codes (401, 404, 429…) and success: true
2AuthAPI key in URL /{apikey}/...Header: x-api-key: YOUR_KEY
3URLs/{apikey}/v1/{mode}/endpoint/v2/endpoint
4Refreshlive / eager mode in path?refresh=true query param
5Parameters & payloadsPer-endpoint v1 params and re-mapped payloadsReworked per endpoint — see the endpoint mapping
6json_pathDocumented in the old APINot supported — filter client-side

How v1 works today​

Knowing this helps you decide what to migrate first.

  • Paths: /{apikey}/v1/{mode}/{endpoint}. The /v1 segment is optional. /me takes no {mode}.
  • Same backend: the {apikey} segment is turned into the x-api-key header internally, and v1 uses the same cache and quotas as v2.
  • Legacy body: success: 1, source, no updatedAt / expiresAt.
  • Real errors: v1 no longer returns HTTP 200 for errors. Failures return a real status code with the v2 error body, so clients that only check success === 0 will miss them.
  • Gone: json_path is not supported, and /gamedata/... answers 410 Gone.

Migration steps​

Do the steps in order. Step 1 is worth doing even if you stay on v1 for now.

Step 1 — Fix error handling​

v1 paths already return real HTTP status codes. Check the status, not success === 0.

const res = await fetch(url);
if (!res.ok) {
const body = await res.json(); // { success: false, message, code }
throw new Error(`${body.code}: ${body.message}`);
}
[ ] Check res.ok / the HTTP status code instead of success === 0
[ ] Handle 401, 403, 404, 429 and 500
[ ] Read the error body as { success: false, message, code }

Details: Errors and status codes.

Step 2 — Move the API key to a header​

# v1
GET /myapikey1234/v1/live/user/SomeHandle

# v2
GET /v2/users/SomeHandle
x-api-key: myapikey1234
[ ] Remove the API key from the URL
[ ] Send x-api-key on every request

Keys must match [A-Za-z0-9_]{32,68}. Details: Authentication.

Step 3 — Update URLs and the fetch mode​

Replace the prefix and translate the mode. You can migrate one endpoint at a time.

v1 modev2
live, eager?refresh=true (costs 1 daily request, 10 for ships)
cache, autoomit ?refresh (always free)
[ ] /{apikey}/v1/{mode}/... → /v2/...
[ ] live / eager → ?refresh=true; cache / auto → no parameter
[ ] Look up each endpoint in the mapping page (paths change, not just the prefix)
[ ] Stop calling /gamedata/... (410 Gone)

Details: Fetch mode and the endpoint mapping.

Step 4 — Adapt parameters and payloads​

Some v1 endpoints were combined or re-shaped by the compatibility layer. Check the ones you use:

[ ] Users: /user/:handle → /users/:handle (or /profile + /organization)
[ ] Organization members: rank / role / main_org → rankIndex / roleIndex / isMainOrg; pageSize is new (default 10)
[ ] Stats: /stats → /funding-goals (funds are now in cents)
[ ] Versions: filter=latest → read data.latest; the response is { latest, versions }
[ ] Progress tracker: /progress-tracker → /progress-tracker/teams
[ ] Progress tracker: /progress-tracker/:team_slug → /progress-tracker/deliverables/by-team-slug/:slug
[ ] Roadmap: apply date_min / date_max / version filters client-side
[ ] Telemetry: always send ?timetable= (no default in v2)
[ ] Ships: classification takes a single value; id filter, page and page_max are removed
[ ] Starmap: ?name= / ?code= / ?id= lookups become path-based routes
[ ] Starmap search: ?name= → ?query=
[ ] Remove json_path — filter client-side

Details per resource: Endpoint mapping.

Step 5 — Parse the v2 response​

// v1
if (response.success === 1) { ... }

// v2
if (response.success === true) { ... }

// Safe for both versions
if (response.success) { ... }
[ ] success is now a boolean (true / false)
[ ] Stop reading `source`; use updatedAt / expiresAt
[ ] Re-check every field you read — v2 returns raw models, v1 re-mapped many of them

Details: Response format.

Step 6 — Optional polish​

[ ] Send If-None-Match with the previous ETag to get 304 instead of re-downloading
[ ] Use updatedAt / expiresAt to drive cache invalidation
[ ] Back off on HTTP 429 and retry after the minute window resets

Details: Conditional headers and Rate limits.


Before / after examples​

# v1
GET /myapikey1234/v1/cache/ships?name=Hornet

# v2
GET /v2/ships?name=Hornet
x-api-key: myapikey1234

Where to go next​

I want to…Go to
Find the v2 equivalent of a v1 endpointEndpoint mapping
Understand a behaviour change (auth, errors, rate limits, headers)Behaviour changes
See what v2 adds that v1 never hadv2-only endpoints
Debug a failing requestTroubleshooting
info

Need help? Join the community Discord server.