Lyria

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.

ParameterDescriptionHeader
titleSong title. Required in field mode; artist, album and duration are optional refinements.X-Title
artistArtist name; "feat." credits are matched too.X-Artist
albumAlbum name, used as a tie-breaker.X-Album
durationTrack 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
idExact 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.

Query string
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
Headers
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.

ParameterDescriptionDefault
formatOne of: lrc, elrc, ttml, json, srt, vtt, txt.lrc
langTranslation language code, e.g. en, tr, pt-BR. 404 lists available languages when missing.
translationinline: original lines followed by their translation · replace: translated text only.inline
synced1 = answer only if time-synced lyrics exist.
download1 = send as a file attachment.
LRC with Turkish translation inline
[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

formatContent-TypeNotes
lrctext/plainLine-synced LRC with ID tags. Unsynced lyrics come back without timestamps.
elrctext/plainEnhanced LRC with <mm:ss.xx> word timings and v1:/v2: duet agents when available.
ttmlapplication/ttml+xmlApple-style TTML; word spans, agents, and translations as x-translation spans.
jsonapplication/jsonLines with start_ms, end_ms, text, optional words[], agent and translation.
srtapplication/x-subripSubtitles; requires synced lyrics (422 otherwise).
vtttext/vttWebVTT with inline word timestamps; requires synced lyrics.
txttext/plainPlain text.

Artwork GET /api/artwork

Alias: /artwork.

ParameterDescriptionDefault
formatredirect: 302 to the public image URL · image: image bytes · json: URLs, size, mime and sizes map.redirect
sizeLongest 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 }
  }
}

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"]
  }
}
Statuscode
400missing_parameter, invalid_parameter, invalid_format
401unauthenticated, invalid_token
403insufficient_scope, ip_not_allowed
404song_not_found, lyrics_not_found, synced_lyrics_not_found, translation_not_found, artwork_not_found
422format_unavailable
429rate_limited, quota_exceeded