Advanced Features
The API supports optional HTTP features that allow you to reduce bandwidth and build more efficient clients.
Conditional Requests (ETags)
ETags allow you to avoid downloading a full response if the data has not changed since your last request. The API supports two conditional request headers:
If-None-Match
The most common pattern. Send the ETag from a previous response; the server will return 304 Not Modified (with no body) if the data is unchanged, or a fresh 200 OK with the new data if it has changed.
GET /v2/users/dymerz HTTP/1.1
Host: API_HOST
x-api-key: YOUR_API_KEY
If-None-Match: "a1b2c3d4e5f6"
| Scenario | Response |
|---|---|
| Data unchanged | 304 Not Modified — no body, use your cached copy |
| Data changed | 200 OK — full response with updated ETag |
If-Match
Sends data only if the current ETag matches the one you provide. Returns 412 Precondition Failed if it does not match.
GET /v2/users/dymerz HTTP/1.1
Host: API_HOST
x-api-key: YOUR_API_KEY
If-Match: "a1b2c3d4e5f6"
Store the ETag response header alongside your cached data. On the next request, send it back via If-None-Match. This is especially useful for polling endpoints like stats or versions.
updatedAt and Last-Modified
Every successful response includes freshness metadata reflecting when the data was last scraped and when it may next be re-scraped.
{
"success": true,
"message": "ok",
"updatedAt": "2026-05-31T10:00:00.000Z",
"expiresAt": "2026-05-31T11:00:00.000Z",
"data": { ... }
}
| Where | Format | Use |
|---|---|---|
updatedAt body field | ISO 8601 string | When data was last scraped from RSI |
Last-Modified header | HTTP-date string | HTTP conditional caching (If-Modified-Since) |
expiresAt body field | ISO 8601 string | Earliest time the data may be automatically re-scraped |
Expires header | HTTP-date string | HTTP-native expiry signal (same value as expiresAt) |
updatedAt and Last-Modified reflect the same point in time. expiresAt and Expires reflect the same point in time — updatedAt + refreshInterval for that endpoint type.
Refresh Intervals
Each endpoint type has a fixed maximum data age. Once that age is exceeded the next request will trigger a background re-scrape automatically — no ?refresh=true required.
| Endpoint group | Max data age |
|---|---|
Users (/v2/users/…), User orgs (/v2/users/…/organizations) | 1 hour |
| Organizations detail/members/search, Versions, Progress Tracker | 6 hours |
| Roadmap, Ships | 12 hours |
| Stats, Starmap search | 24 hours |
| Telemetry, Starmap data | 48 hours |
Use expiresAt to schedule your next poll precisely — there is no point re-fetching before that timestamp unless you add ?refresh=true.
Refresh Intervals
Each endpoint type has a fixed maximum data age — determined at deployment. Once that threshold is exceeded, the next request triggers a background re-scrape automatically — no ?refresh=true required.
Pair these intervals with cacheExpiresAt (see above) — when your cached copy reaches that timestamp, the next request will automatically get refreshed data without any quota cost.
Pair these intervals with ETags: if you poll more often than the refresh interval, 304 Not Modified responses tell you nothing has changed without spending quota.
For live status of manual quota resets and cache maintenance jobs, check GET /managements/status (no API key required):
GET /managements/status HTTP/1.1
Host: API_HOST{
"success": true,
"message": "ok",
"data": {
"quotaReset": {
"lastAt": "2025-05-18T00:00:00.000Z",
"nextAt": "2025-05-19T00:00:00.000Z"
},
"cacheRefresh": {
"lastAt": "2025-05-18T14:00:00.000Z",
"nextAt": "2025-05-18T15:00:00.000Z"
}
}
}