Skip to content

Conventions

Use https://haneoka.org as the production origin. The direct catalog routes are:

GET /api/v1/{resource}
GET /api/v1/{resource}/{id}
GET /api/v1/{resource}/views/{view}
GET /api/v1/{resource}/views/{view}/{id}
GET /api/v1/{resource}/relations/{relation}/{key}

These routes use the current intl server by default. Add ?server=jp or another slug from GET /api/v1/releases to select a different active server. The explicit /api/v1/servers/{server}/... form reaches the same catalog handler and adds the release option used by reproducible builds.

resource, id, view, relation, and key are data-defined values. Read the catalog manifest or an index response before constructing a route. Top-level groups such as releases, servers, account, me, community, and garupa keep their own API routes and are not catalog resource names. URL-encode each dynamic segment; preserve / only where the documented route accepts a path.

Try a direct route:

GET /api/v1/bands
Not sent yet

JSON responses use application/json; charset=utf-8. Catalog index responses normally use an object keyed by entity ID. Entity values keep the source DTO shape. For example, a song uses musicId, localized arrays such as musicTitle, difficulty records, and media paths; an events resource can return { "entries": {}, "hasGameEvents": false }. Code against the documented fields for the resource you requested and preserve additional fields.

The API does not add a universal id, title, or data wrapper to provider DTOs. An index key is the lookup ID even when the value uses a resource-specific ID field. A null field means the source currently has no value for that property.

HeaderMeaning
X-Request-IdCorrelation ID for an error or diagnostic report.
X-Haneoka-Release-IdCurrent release that served a server-scoped response.
X-Haneoka-Source-IdSource snapshot associated with that release.
ETagRepresentation validator for conditional requests.
Cache-ControlFreshness and revalidation policy selected by the service.
Content-RangeReturned byte range or bytes */size for an unsatisfied range.

Current aliases can change when the service promotes a new catalog. Store the release headers with a cache entry when you need to explain which data a user saw. Applications that need stable replay can switch to an explicit release request; the advanced release page documents that workflow.

Repeat id for a batch request:

GET /api/v1/songs?id=100001&id=100002

Catalog batches return { "items": { ... }, "missing": [ ... ] }. The service sorts and de-duplicates IDs for its cache key. A missing ID is a result for that ID, not a failed request.

The catalog manifest declares views and relations for each resource. A view has its own index and entity shape. A relation returns either canonical entities keyed by ID (valueMode: "ids") or provider records (valueMode: "records"). Follow the manifest’s names and shapes; values can differ between resources.

Honor ETag and Cache-Control. Send If-None-Match to receive 304 when a representation is unchanged. Resolve relative media paths such as /assets/intl/... and /runtime/intl/... against https://haneoka.org.

Binary routes declare their media type and may support a single byte range. A valid partial response is 206; an unsatisfied range is 416 with Content-Range: bytes */<size>. Do not retry a 416 unchanged.

Public catalog, media, Sonolus, and Bestdori reads do not require a session. Community writes, profile changes, preferences, uploads, and Better Auth operations use HTTP-only cookies and same-origin browser requests:

await fetch("/api/v1/account/profile", {
credentials: "include",
method: "PATCH",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({ bio: "Hello", version: 4 }),
});

Keep session cookies out of logs and client bundles. Each authenticated page documents the request body, conflict fields, and moderation state for that operation.