Repository navigation
Versions
Groups multiple song rows together as versions of the same underlying track — e.g. a released mix and a leaked earlier take, or several titled variants like "v1", "v2", "TV Mix". Each row links one song_id to a shared group_id; every song in a group shares the same title (the display name for the group, e.g. "She's The One"), while each song keeps its own version label (e.g. "v1") distinguishing it from its groupmates.
Reads require no auth. Writes (POST/PATCH) require an editor or admin token.
{
"id": 501,
"song_id": 94086,
"group_id": 94086,
"version": "v1",
"title": "She's The One",
"created_at": "2026-03-04T12:00:00Z",
"created_by": "freakypallet"
}group_id is just the song_id of whichever song originally anchored the group — it has no meaning beyond being a shared key. title is null until an editor names the group; version is null until an editor labels that specific song.
The one filtered read the API supports server-side. Returns the paginated envelope with 0 or 1 result — empty means the song isn't linked into any group.
{
"count": 1,
"next": null,
"previous": null,
"results": [ { "id": 501, "song_id": 94086, "group_id": 94086, "version": "v1", "title": "She's The One", ... } ]
}GET /versions/{song_id}/{id}/ fetches a single version row directly by its own id, unpaginated, instead of the song-filtered list above.
The list endpoint does not apply query params (group_id, search, title) server-side — any filtering by group or title has to happen client-side. Pass ?all=true to get every row in one response instead of paging through it (same bulk-mode convention /songs/ supports).
GET /versions/?all=true
// Response: a plain array (not the paginated envelope)
[
{ "id": 501, "song_id": 94086, "group_id": 94086, "version": "v1", "title": "She's The One", ... },
{ "id": 502, "song_id": 94112, "group_id": 94086, "version": "v2", "title": "She's The One", ... },
{ "id": 503, "song_id": 95230, "group_id": 95230, "version": null, "title": null, ... }
]
POST /versions/
Authorization: Token <token>
Content-Type: application/json
{
"song_id": 94112,
"group_id": 94086,
"version": "v2",
"title": "She's The One"
}
Used both to link a previously-ungrouped song into an existing group and to seed a brand-new group (pass a group_id no other row uses yet — the app conventionally uses one of the two songs' own song_id).
PATCH /versions/{song_id}/
Authorization: Token <token>
Content-Type: application/json
{ "group_id": 94086, "title": "She's The One" }
Any subset of group_id, version, title may be sent. There is no bulk-write endpoint — merging two groups or renaming a group's title means sending one PATCH per affected song.
-
Link two ungrouped songs: create two rows sharing a new
group_id(e.g. the lower of the two song IDs). -
Add an ungrouped song to an existing group:
POSTone row with that group'sgroup_idandtitle. -
Merge two existing groups: fetch every row in both groups (via
?all=true), thenPATCHevery row in the losing group to the survivinggroup_id— and if only one side had atitleset,PATCHthat title onto every row in the merged group so all members agree. -
Rename a group's title:
PATCH{ title }onto every row whosegroup_idmatches.