Skip to content

Responses

JSON routes return a common envelope:

type ApiEnvelope<T> = {
data: T;
meta: {
registry: string;
apiVersion: string;
};
nextCursor?: string;
};

nextCursor only appears on paginated list routes when another page exists.

meta.registry identifies the public API deployment, not the canonical Registry database.

meta.apiVersion identifies the public route version.

Metadata does not prove that an individual record is complete. Use source, confidence and freshness routes for that.

Errors use the same metadata boundary:

{
"error": {
"code": "not_found",
"message": "Entity not found."
},
"meta": {
"registry": "blackrelay-api",
"apiVersion": "v1"
}
}

Common codes:

Code Meaning
bad_request Request parameters were not usable.
not_found The route or record was not found.
method_not_allowed The route only supports GET and HEAD.
rate_limited The client exceeded a public request limit.
internal_error The Worker failed while handling the request.
not_ready A readiness dependency is unavailable.

Errors are intentionally small. Do not parse the human-readable message for application logic; use the HTTP status and error.code.

Status Typical Meaning
200 Request succeeded.
204 Successful OPTIONS preflight with no body.
400 Query parameters were invalid or unusable.
404 Route or record was not found.
405 Method is not supported.
429 Public request limit was exceeded.
500 Unexpected Worker or storage failure.
503 Readiness dependency is unavailable.

The public API supports:

Method Behaviour
GET Return the response body.
HEAD Return the same status and headers without a body.
OPTIONS Return CORS preflight headers.

State-changing methods are rejected.

JSON responses use:

Content-Type: application/json; charset=utf-8
Access-Control-Allow-Origin: *
Access-Control-Allow-Methods: GET, HEAD, OPTIONS
Access-Control-Allow-Headers: Content-Type
X-Content-Type-Options: nosniff

Most read responses use short public cache headers. Health, readiness and errors use no-store.

The API is public read-only. CORS allows public browser clients to read the API but it does not grant write access because state-changing methods are rejected.

The API does not require credentials for public reads. Clients should not send cookies or bearer tokens to public routes.

limit defaults to 50.

Invalid or missing limits fall back to the default.

The maximum list limit is 200.

Clients should prefer small page sizes for interactive views. Use exports when you need bulk data.

Public request limits are enforced by Cloudflare Worker Rate Limit bindings after the Worker checks its cache. Cache hits do not spend the route budget. Uncached GET and HEAD requests are grouped by route class and client IP:

Route class Paths Limit
General API /v1/* except the routes below 300 requests per minute
Operations /metrics, /v1/metrics, /v1/ops/* 60 requests per minute
Exports /v1/exports/* 30 requests per minute

When a request is limited, the API returns HTTP 429, Retry-After: 60 and error.code set to rate_limited. Clients should honour Retry-After, keep interactive page sizes small and use cached export files for bulk reads.

Cursors are opaque. Clients should store and pass them back unchanged. Do not parse or construct cursors in client code.

Entity and current-state lists are ordered by Registry sort key and id.

Events and killmails are ordered newest first by occurrence time and id.

Time fields are UTC timestamps. Treat them as instants, not as local player time.

When displaying time to users:

  • keep the raw UTC timestamp available for copy/debug
  • format local time in the UI if useful
  • avoid mixing cycle labels with local timezone assumptions

Missing fields are different from negative claims.

If a system coordinate, tribe name, killer name or source relation is absent, read that as:

not present in this export or not resolved by the current importer

Do not treat it as:

the value does not exist

For user-facing tools:

  • show displayName when present
  • keep stable ids copyable somewhere in the interface
  • show source and confidence for important claims
  • avoid displaying internal prefixes when a clean id is available
  • do not hide unresolved ids if they are the only sourced value