API
| Endpoint | Description |
|---|---|
| GET /api/songdb/intl | INTL song database: every chart currently playable on CHUNITHM International. |
Everything listed here is public and needs no authentication. New endpoints will be added to this list.
GET /api/songdb/intl
https://chunimaru.fuwamofu.net/api/songdb/intl
A public, machine-readable database of every song currently playable on CHUNITHM International, one entry per song with one object per live chart. Unreleased, deleted, and banned songs are not included; availability is maintained against CHUNITHM-NET itself.
The endpoint needs no authentication and CORS is open, so it can be called from servers, scripts, and browser code alike. The database updates automatically alongside site data; new songs usually appear the day they are added.
Synopsis
$ curl -I --compressed https://chunimaru.fuwamofu.net/api/songdb/intl
HTTP/2 200
content-type: application/json; charset=utf-8
content-encoding: gzip
content-length: 168819
etag: W/"f334bb52036831a6a0f8dfb489ca4be9a2cea5e9"
cache-control: public, max-age=300
x-ratelimit-limit: 30
x-ratelimit-remaining: 29
access-control-allow-origin: *
vary: Accept-Encoding
Request
GET returns the full document. HEAD returns the same headers with no body. There is no authentication and there are no query parameters. Both request headers below are optional but strongly recommended.
| Header | Description |
|---|---|
Accept-Encoding: gzip |
Compresses the response to about a tenth of its raw size (about 170 KB instead of 1.7 MB). curl users can simply pass --compressed. |
If-None-Match |
Send the ETag value from a previous response, exactly as received. If the database has not changed, the answer is 304 with an empty body. |
Response
| Header | Description |
|---|---|
Content-Type |
application/json; charset=utf-8 on every response that has a body (200, 429, 503). |
ETag |
Validator for conditional requests. It may be delivered in weak form (W/"..."); send it back exactly as received. |
Cache-Control |
public, max-age=300 on 200 and 304; error responses (429, 503) send no-store instead. Cache for up to five minutes, then revalidate with If-None-Match. |
Content-Encoding |
gzip when the request allowed it; absent otherwise. |
Content-Length |
Body size in bytes, after compression when gzip applies. HEAD returns it too, so a download can be sized in advance. |
Vary |
Accept-Encoding. Caches must key the response on the requested encoding. |
X-RateLimit-Limit |
Requests allowed per window for your IP address. |
X-RateLimit-Remaining |
Requests left in the current window. |
Access-Control-Allow-Origin |
*. The endpoint can be called directly from browser code. |
| Status | Meaning |
|---|---|
| 200 | Success. The full document is in the body. |
| 304 | Not modified. Your cached copy is current and the body is empty. Still counts toward the rate limit. |
| 429 | Rate limit exceeded. A JSON body describes the limit, and the Retry-After header says how many seconds to wait. |
| 503 | The database is unavailable on the serving deployment. Retry later; if it persists, report it. |
Rate Limit
Currently 30 requests per hour per IP address (fixed window), and 304 responses count too; the X-RateLimit-Limit header on every response is the authoritative value. Exceeding the limit returns 429 with a Retry-After header, and X-RateLimit-Remaining shows where you stand.
The data changes at most a few times a week. Cache the file, revalidate with If-None-Match, and poll no faster than hourly; anything more gains nothing.
Schema
formatVersion is currently 1 and only changes on breaking schema changes; pin against it if you parse the document programmatically. Field names below are literal.
| Top-Level Field | Description |
|---|---|
format | Always chunimaru-songdb. |
formatVersion | Schema version, currently 1. Bumped only on breaking changes. |
generatedAt | Build timestamp, UTC, ISO 8601. |
server | Always intl. |
gameVersion | INTL game version label at build time. |
newSongCutoff | The old/new rating pool split date. isNew is release >= newSongCutoff. |
songCount, chartCount | Number of entries in songs, and of chart objects across all of them. |
difficulties | Canonical difficulty order: BAS, ADV, EXP, MAS, ULT. WORLD'S END is out of scope. |
homepage | The ChuniMaru site. |
notice | Usage and attribution notes. |
songs | The database itself, sorted by idx ascending. |
| Song Field | Description |
|---|---|
idx | CHUNITHM's stable numeric song identifier. |
id | Chart-database hash identifier for the song. |
title, artist, genre | As shown in game. |
bpm | Song BPM. |
release | INTL release date, YYYY-MM-DD. |
releaseVersion | Game version the song released in on INTL. |
releaseVersionValue | The numeric code CHUNITHM-NET uses for that version. |
isNew | true when the song counts toward the NEW side of the rating split. |
img | Jacket image hash. |
jacket | Absolute jacket URL, WebP. |
charts | Object keyed by difficulty. Only live charts are present; a missing key means that difficulty is not playable on INTL. |
| Chart Field | Description |
|---|---|
level | Numeric level as tracked by the chart database. |
levelDisplay | In-game display band derived from level: x.0 to x.4 shows as "x", x.5 and above as "x+". |
const | Chart constant used for rating calculation. |
maxCombo | Maximum combo. 0 when not yet recorded upstream. |
isConstUnknown | true when the constant is a community estimate rather than a verified value; treat it as approximate. |
Example (excerpt of a real entry; two of its four charts shown)
{
"format": "chunimaru-songdb",
"formatVersion": 1,
"generatedAt": "2026-08-05T08:57:14+00:00",
"server": "intl",
"gameVersion": "X-Verse-X",
"newSongCutoff": "2025-12-10",
"songs": [
{
"idx": 2948,
"id": "b6144bf73037e116",
"title": "THE TRiANGLE",
"artist": "Yuta Imai",
"genre": "ゲキマイ",
"bpm": 230,
"release": "2026-07-30",
"releaseVersion": "CHUNITHM X-VERSE-X",
"releaseVersionValue": "20",
"isNew": true,
"img": "773b590c9a43452c",
"jacket": "https://reiwa.f5.si/jackets/chunithm/773b590c9a43452c.webp",
"charts": {
"EXP": { "level": 13, "levelDisplay": "13", "const": 13.3, "maxCombo": 1919, "isConstUnknown": false },
"MAS": { "level": 15, "levelDisplay": "15", "const": 15, "maxCombo": 2709, "isConstUnknown": false }
}
}
]
}
Examples
Download, compressed
curl -s --compressed -o songdb.json \
https://chunimaru.fuwamofu.net/api/songdb/intl
Re-fetch only when changed
# first fetch: keep the ETag from the response headers
curl -s -D headers.txt --compressed -o songdb.json \
https://chunimaru.fuwamofu.net/api/songdb/intl
grep -i '^etag:' headers.txt
# later: 304 means your copy is still current
curl -s --compressed -o songdb.json -w "%{http_code}\n" \
-H 'If-None-Match: W/"PASTE-ETAG-VALUE-HERE"' \
https://chunimaru.fuwamofu.net/api/songdb/intl
Browser fetch
const res = await fetch("https://chunimaru.fuwamofu.net/api/songdb/intl");
if (!res.ok) throw new Error("HTTP " + res.status);
const db = await res.json();
console.log(db.gameVersion, db.songCount + " songs");
Quick queries with jq
U=https://chunimaru.fuwamofu.net/api/songdb/intl
curl -s --compressed $U | jq '.songCount'
curl -s --compressed $U | jq '[.songs[] | select(.isNew)] | length'
curl -s --compressed $U | jq -r '.songs[] | select(.charts.MAS.const >= 15.5) | .title'
Notes
- Some charts carry isConstUnknown: true, community-estimated constants, mostly on lower difficulties. Treat those values as approximate.
- Membership means playable on the INTL cabinet right now. Per-account unlock state is not modeled.
- Data is community-maintained and provided as is. Chart data originates from the reiwa/chunirec dataset; availability is checked against CHUNITHM-NET.
- Not affiliated with SEGA. CHUNITHM is a trademark of SEGA.