API documentation
Lyrics, artwork and metadata served from the Lyria library.
Authentication
Every request needs a bearer token. Create one in the dashboard, or ask an administrator for a token with custom limits. Send it in the Authorization header (or X-API-Key).
curl -H "Authorization: Bearer lyr_xxxxxxxx_…" "https://lyria.kaemit.cc/api/metadata?title=Yesterday"
Tokens can be limited to certain endpoints (lyrics, artwork, metadata, search), to IP ranges, a daily quota and an expiry date. Calling an endpoint outside the token's scope returns 403 insufficient_scope.
Song lookup
All endpoints find a song the same way. Results only ever come from this server's database.
| Parameter | Description | Header |
|---|---|---|
| title | Song title. Required in field mode; artist, album and duration are optional refinements. | X-Title |
| artist | Artist name; "feat." credits are matched too. | X-Artist |
| album | Album name, used as a tie-breaker. | X-Album |
| duration | Track length in seconds (decimals allowed). Songs more than 15 s off are excluded. | X-Duration |
| query (q) | Free-text mode instead of title: "artist song", "song artist", aliases… | X-Query |
| id | Exact song UUID; skips matching. | X-Id |
Any parameter may be sent as an X-… header instead of the query string; percent-encode non-ASCII header values. The query string wins when both are present. Responses include X-Lyria-Song-Id and X-Lyria-Match-Score.
https://lyria.kaemit.cc/lyrics?query=bohemian%20rhapsody
https://lyria.kaemit.cc/lyrics?title=Bohemian%20Rhapsody&artist=Queen&album=A%20Night%20at%20the%20Opera&duration=354
curl "https://lyria.kaemit.cc/api/lyrics" \
-H "Authorization: Bearer $LYRIA_TOKEN" \
-H "X-Title: Bohemian Rhapsody" -H "X-Artist: Queen" -H "X-Duration: 354" -H "X-Format: ttml"
Lyrics GET /api/lyrics
Aliases: /lyrics, /lyric.
| Parameter | Description | Default |
|---|---|---|
| format | One of: lrc, elrc, ttml, json, srt, vtt, txt. | lrc |
| lang | Translation language code, e.g. en, tr, pt-BR. 404 lists available languages when missing. | |
| translation | inline: original lines followed by their translation · replace: translated text only. | inline |
| synced | 1 = answer only if time-synced lyrics exist. | |
| download | 1 = send as a file attachment. |
[ti:Yesterday]
[ar:The Beatles]
[00:01.20]Yesterday, all my troubles seemed so far away
[00:01.20]Dün, tüm dertlerim çok uzak görünüyordu
[00:06.85]Now it looks as though they're here to stay
Formats
| format | Content-Type | Notes |
|---|---|---|
| lrc | text/plain | Line-synced LRC with ID tags. Unsynced lyrics come back without timestamps. |
| elrc | text/plain | Enhanced LRC with <mm:ss.xx> word timings and v1:/v2: duet agents when available. |
| ttml | application/ttml+xml | Apple-style TTML; word spans, agents, and translations as x-translation spans. |
| json | application/json | Lines with start_ms, end_ms, text, optional words[], agent and translation. |
| srt | application/x-subrip | Subtitles; requires synced lyrics (422 otherwise). |
| vtt | text/vtt | WebVTT with inline word timestamps; requires synced lyrics. |
| txt | text/plain | Plain text. |
Artwork GET /api/artwork
Alias: /artwork.
| Parameter | Description | Default |
|---|---|---|
| format | redirect: 302 to the public image URL · image: image bytes · json: URLs, size, mime and sizes map. | redirect |
| size | Longest edge in pixels: 64, 128, 256, 300, 512, 600, 1000, 1200. Never upscales. | original |
Image URLs (/media/artwork/<uuid>.jpg) are public, unguessable and cached for a year, so they can be embedded directly.
Metadata GET /api/metadata
Alias: /metadata. Returns the best match with title, artist, album, album artist, composer, genre, year, track/disc numbers, duration, ISRC, BPM, label, aliases, audio properties, lyric availability (sync type and translation languages) and artwork URLs.
{
"data": {
"id": "0192f1c4-…",
"title": "Yesterday",
"artist": "The Beatles",
"duration": 125.4,
"lyrics": { "available": true, "sync_type": "line", "translations": ["tr"] },
"artwork": { "url": "https://lyria.kaemit.cc/media/artwork/….jpg", "width": 1200, "height": 1200 },
"match": { "score": 0.97 }
}
}
Search GET /api/search
Alias: /search. Same lookup parameters, plus limit (1–25, default 10). Returns ranked songs in data.
Rate limits
Each token has a per-minute limit (its own, or its owner's) and optionally a daily quota. There is also a per-IP limit. Every response includes:
X-RateLimit-Limit: 60
X-RateLimit-Remaining: 59
X-RateLimit-Reset: 1761400000
X-Quota-Remaining: 9999 (tokens with a daily quota)
Over the limit you get 429 with Retry-After.
Errors
Errors are always JSON, whatever format was requested:
{
"error": {
"status": 404,
"code": "translation_not_found",
"message": "No de translation for this song",
"available": ["en", "tr"]
}
}
| Status | code |
|---|---|
| 400 | missing_parameter, invalid_parameter, invalid_format |
| 401 | unauthenticated, invalid_token |
| 403 | insufficient_scope, ip_not_allowed |
| 404 | song_not_found, lyrics_not_found, synced_lyrics_not_found, translation_not_found, artwork_not_found |
| 422 | format_unavailable |
| 429 | rate_limited, quota_exceeded |