v1 → v2 Mapping Reference
:::info Audience This is a lookup page for existing v1 users. For the ordered procedure, read the Migration Guide. New users can ignore this page and start from the Quickstart. :::
Jump to: Endpoint mapping · Behaviour changes · v2-only endpoints
Endpoint mapping
v1 paths below are written without the /{apikey}/v1/{mode} prefix. v2 paths are relative to /v2.
| Resource | v1 | v2 |
|---|---|---|
| Me | /me | /me |
| Users | /user/{handle} | /users/{handle} |
| Organizations | /organization/{sid} | /organizations/{sid} |
| Org members | /organization_members/{sid} | /organizations/{sid}/members |
| Stats | /stats | /funding-goals |
| Ships | /ships | /ships |
| Versions | /versions | /versions |
| Roadmap | /roadmap/{board} | /roadmap/{board} |
| Progress tracker | /progress-tracker | /progress-tracker/teams |
| Telemetry | /telemetry/{version} | /telemetry/{version} |
| Starmap | /starmap/... | /starmap/... (reworked) |
Me
| v1 | v2 |
|---|---|
GET /{apikey}/v1/me | GET /v2/me with x-api-key header |
Users
v1 returned the profile, main organization and affiliations in a single call. v2 splits them.
| v1 | v2 |
|---|---|
GET /user/{handle} | GET /v2/users/{handle} |
(included in /user/{handle}) | GET /v2/users/{handle}/profile |
(included in /user/{handle}) | GET /v2/users/{handle}/organization |
Organizations
| v1 | v2 |
|---|---|
GET /organization/{sid} | GET /v2/organizations/{sid} |
GET /organization_members/{sid} | GET /v2/organizations/{sid}/members |
| (no v1 endpoint) | GET /v2/organizations/search?... |
Organization members query parameters:
| v1 | v2 | Notes |
|---|---|---|
page | page | Same |
| (fixed at 32 per page) | pageSize | v2 default is 10 |
rank | rankIndex | |
role | roleIndex | |
main_org | isMainOrg | |
| (none) | search | New — free-text member search |
/v2/organizations/search accepts search, page, sort, size, activity, commitment, languages, model, recruiting and roleplay.
Stats → Funding goals
| v1 | v2 |
|---|---|
GET /stats | GET /v2/funding-goals |
?chart=hour|day|week|month is supported on both (default day). v2 returns the raw funding model: funds is expressed in cents (the v1 layer divides it by 100), and the v1-only current_live / current_ptu / current_etf fields are not part of the v2 funding response. Use /v2/versions for the live version.
Ships
| v1 | v2 |
|---|---|
GET /ships | GET /v2/ships |
Ship filters are applied by the API against its cached full catalog. Supported on both: name, length_min/max, crew_min/max, price_min/max, mass_min/max.
Differences:
classificationtakes a single value in v2 (v1 accepted a comma-separated list and merged the results).- The
idfilter is removed. pageandpage_maxare not supported.- v1 converted numeric fields to numbers and rewrote
urlas a relative path; v2 returns the raw ship model.
Versions
| v1 | v2 |
|---|---|
GET /versions | GET /v2/versions |
GET /versions?filter=latest | GET /v2/versions → read data.latest |
v1 returned an array of version strings. v2 returns { "latest": {...}, "versions": [...] } with full version objects. The filter query parameter does not exist in v2.
Roadmap
| v1 | v2 |
|---|---|
GET /roadmap/{board} | GET /v2/roadmap/{board} |
board values are unchanged: starcitizen or squadron42.
The date_min, date_max and version filters are applied by the v1 layer only. The v2 handler returns the full board — filter client-side.
v1 also normalised released to 0 / 1 and added category_name to each card; v2 returns the raw roadmap model.
Progress tracker
| v1 | v2 |
|---|---|
GET /progress-tracker | GET /v2/progress-tracker/teams |
GET /progress-tracker/{team_slug} | GET /v2/progress-tracker/deliverables/by-team-slug/{slug} |
| (no v1 endpoint) | GET /v2/progress-tracker/teams/by-slug/{slug} |
| (no v1 endpoint) | GET /v2/progress-tracker/deliverables |
| (no v1 endpoint) | GET /v2/progress-tracker/deliverables/by-slug/{slug} |
/progress-tracker → /progress-tracker/teams — the path suffix is required in v2. Date fields (startDate, endDate, updateDate) are ISO strings in v2; v1 formatted them as RFC 1123 (Mon, 18 Jan 2021 00:00:00 +0000).
Telemetry
| v1 | v2 |
|---|---|
GET /telemetry/{version} | GET /v2/telemetry/{version}?timetable=MONTH |
timetable (DAY, WEEK, MONTH) is required in v2. v1 defaulted to MONTH.
Starmap
v1 used a ?name= / ?code= / ?id= query on each resource. v2 uses dedicated path-based routes, and every resource now has lookups by id, name and code.
| v1 | v2 |
|---|---|
GET /starmap/search?name=X | GET /v2/starmap/search?query=X |
GET /starmap/systems | GET /v2/starmap/systems |
GET /starmap/systems?name=X | GET /v2/starmap/systems/by-name/{name} |
GET /starmap/star-system?code=X | GET /v2/starmap/star-systems/{code} |
GET /starmap/object?code=SYS.A.B | GET /v2/starmap/objects/{systemCode}/by-code/{code} |
GET /starmap/affiliations | GET /v2/starmap/affiliations |
GET /starmap/affiliations?name=X | GET /v2/starmap/affiliations/by-name/{name} |
GET /starmap/species | GET /v2/starmap/species |
GET /starmap/species?name=X | GET /v2/starmap/species/by-name/{name} |
GET /starmap/tunnels | GET /v2/starmap/tunnels |
GET /starmap/tunnels?id=X | GET /v2/starmap/tunnels/{id} |
In the v1 object lookup, the system code is the first segment of code (STANTON.PLANETS.STANTON2 → STANTON).
v1 also converted numeric strings to numbers in starmap payloads (positions, sizes, ids…); v2 returns the raw models.
Behaviour changes
Authentication
v1 took the key in the URL (/{apikey}/v1/live/user/SomeHandle). v2 takes it in a header on every request:
GET /v2/users/SomeHandle
x-api-key: YOUR_API_KEY
| Condition | Status |
|---|---|
| Missing header | 401 — API key is required in x-api-key header |
Does not match [A-Za-z0-9_]{32,68} | 401 — Invalid API key format |
| Unknown key | 401 — Invalid API key |
| Account blocked | 403 |
?refresh=true with no daily quota left | 429 — Daily request quota exhausted |
Fetch mode → ?refresh
v1 exposed a {mode} path segment controlling cache behaviour. v2 replaces it with a single boolean query parameter. An unknown v1 mode returns 404 V1 mode not found.
| v1 mode | v2 equivalent | Description |
|---|---|---|
live | ?refresh=true | Scrape RSI in real time. Costs quota. |
cache | ?refresh=false (default) | Return cached data, re-scraped automatically once expired. Free. |
auto | ?refresh=false (default) | Return cached data, re-scraped automatically once expired. Free. |
eager | ?refresh=true | Force a live scrape — same as live |
The API manages cache freshness server-side. Omit ?refresh for cached data, or pass ?refresh=true when live data is needed.
Only ?refresh=true consumes your daily quota.
It costs 1 daily request (10 for /v2/ships). Requests without it are free, including the automatic re-scrape triggered when the cache has expired.
Response format
// v1
{
"success": 1,
"message": "ok",
"data": { ... },
"source": "live"
}
// v2
{
"success": true,
"message": "ok",
"data": { ... },
"updatedAt": "2024-01-15T12:00:00.000Z",
"expiresAt": "2024-01-15T13:00:00.000Z"
}
successis a boolean in v2, not an integer.sourceis removed — replaced byupdatedAt(when data was scraped) andexpiresAt(when the cache expires). Both are ISO 8601 strings when present.datais the raw v2 model. v1 re-mapped many endpoints (see the endpoint mapping).
Errors and status codes
Errors use the same body and status codes on both v1 and v2 paths:
// Previously (v1) — HTTP 200, success: 0
{
"success": 0,
"message": "Apikey is not correct.",
"data": null,
"source": null
}
// Now (v1 and v2) — HTTP 401
{
"success": false,
"message": "Invalid API key",
"code": 401
}
| Code | Meaning |
|---|---|
200 | Success |
304 | Not Modified — If-None-Match matched the ETag |
400 | Bad Request — invalid or unknown query params |
401 | Unauthorized — missing or invalid API key |
403 | Forbidden — account blocked or insufficient permissions |
404 | Not Found (also: unknown v1 {mode}) |
410 | Gone — /gamedata/... |
429 | Too Many Requests — quota or scrape rate limit exceeded |
500 | Internal Server Error |
For the full list of messages, see Error Codes.
Rate limits
| v1 (legacy) | v2 | |
|---|---|---|
| Quota tracked | Per live / eager request | Per ?refresh=true request (1, or 10 for ships) |
| Quota exceeded | HTTP 200, "success": 0 | HTTP 429 (on both v1 and v2 paths) |
| Per-minute request limit | None | 120 requests per API key (or IP) by default, cached or not, with X-RateLimit-* headers |
| Per-minute scrape limits | None | 60 per API key and 60 global by default (Redis-backed) |
| Privileged accounts | Skip quota checks | Same (handled server-side) |
On HTTP 429, back off and retry after the current minute window resets.
Conditional headers
ETag support exists on both versions. Cache metadata headers are v2-only.
| Header | v1 | v2 |
|---|---|---|
ETag | Returned on success (weak, W/"...") | Returned on success (weak, W/"...") |
If-None-Match | Supported → 304 | Supported → 304 |
If-Match | Not supported | Not supported |
Last-Modified | Not returned | Returned |
Expires | Not returned | Returned |
X-Data-Source | Not returned | Returned |
X-Quota-Consumed | Returned | Returned |
X-RateLimit-* | Returned | Returned |
Send If-None-Match with the ETag from a previous response. If the data hasn't changed, the server returns 304 Not Modified with no body. See HTTP caching.
Removed features
json_path. The old API supported ?json_path=$.data.some.path on all endpoints. Neither v1 nor v2 supports it. Filter client-side:
// Old
GET /apikey/live/ships?json_path=$.data[0].name
// v2 — simple case
const { data } = await res.json();
const name = data[0].name;
// v2 — complex filtering (use a library like jsonpath-plus)
import { JSONPath } from 'jsonpath-plus';
const names = JSONPath({ path: '$.data[?(@.size=="large")].name', json: body });
Gamedata. /gamedata/... routes still exist under /{apikey}/v1/gamedata/... but only answer 410 Gone. They are not present in v2.
Unknown query parameters. v2 endpoints that validate their query with a DTO (ships, organizations, funding goals, telemetry…) reject unknown query parameters with 400. Remove v1-only parameters rather than leaving them on the request.
v2-only endpoints
These did not exist in v1. Useful if you are migrating and want to simplify, and a quick overview if you are new.
| Endpoint | Description |
|---|---|
DELETE /v2/me | Delete the API key you are calling with (permanent; the login cannot register again) |
DELETE /v2/me/unregister | Unregister the account and its API key (same effect, different message) |
GET /v2/organizations/search | Search organizations by activity, size, language… |
GET /v2/starmap/routes | Route search between star systems |
GET /v2/progress-tracker/deliverables | List every deliverable, plus lookups by slug |
GET /v2/starmap/.../by-name, by-code, {id} | Direct lookups for systems, objects, affiliations, species and tunnels |
POST /management/auth/renew | Rotate your API key. Dashboard route: needs the login JWT as a bearer token, not x-api-key |
GET /management/health/check | Public health check (MongoDB + Redis) |
GET /management/status | Next and last quota reset times (no API key needed) |
GET /swagger, /swagger.json | Interactive API explorer and OpenAPI spec for v2 |
v2 responses include updatedAt and expiresAt when cache metadata is available — use them to drive smarter cache invalidation instead of guessing TTLs.