# Musiquay — Feature: Music Layer > The music layer: tracks, albums, playlists, and play reports. One recording, many encodings. The recording is the identity; the files are editions of it. ## Overview Musiquay's core music objects are four event kinds: | Kind | Object | Replaceability | |------|--------|----------------| | **32210** | Track — a specific recording, carrying every published digital encoding | Addressable | | **32211** | Album — an ordered collection of tracks (the release identity) | Addressable | | **32212** | Playlist — a named, ordered collection of tracks | Addressable | | **3221** | Play report — a record of a listener playing a track | Regular (immutable) | Track, album, and playlist are referenced by address (`::`) - never by event id, because they are replaced on every update. Play reports are regular events, referenced by id: one play, one immutable record. Paid assets add an access layer on top: signed access filters gate the bytes, private delivery receipts record what was served, and host aggregates publish the totals. That layer is specified in [FEATURES_ACCESS.md](./FEATURES_ACCESS.md). ## Track (Kind 32210) A track event identifies the recording — not any particular file. A single track event carries every digital encoding of that recording published to date, each identified by a standard codec specification, each pointing at a Blossom blob. This mirrors how the physical world works: the vinyl pressing, the CD replication, and the digital master are all *editions of the same recording*. On Musiquay, the digital encodings are the editions. The track event is published by the **person who took the master, encoded it, and uploaded the binaries** — the publisher. That pubkey is the event author and controls the encoding list. The artist or artists are tagged participants, not necessarily the author: an artist can publish their own recordings, or a label/engineer can publish on their behalf (credit confirmation and scene police validation then apply exactly as in [FEATURES_CREDITS.md](./FEATURES_CREDITS.md)). ### The Recording is the Identity A track event is not "file X uploaded by Y." It is "this recording," stable across: - **Multiple encodings** — the same master as FLAC, as MP3 V0, as Opus, each with its own blob. - **Encodings added over time** — the lossy versions may arrive days or months after the initial release. - **Format migration** — new formats (e.g. adding Opus) or higher-resolution masters published later. The track event is **addressable (replaceable)**: when a new encoding is released, the publisher republishes the event containing all previous encodings plus the new one. The latest event replaces the previous one, so readers always see the complete encoding set. The address is the permanent identity of the recording; the event id changes with every update, so references MUST use `a` tags, never `e` tags. ### Metadata from Standard Tag Annotations The track's metadata tags are modeled on the fields that already exist in the wild: ID3 frames (MP3), Vorbis comments, and the MusicBrainz schema. The mapping is explicit so that import tools can translate existing tagged files into track events and vice versa. ### Blossom Links for Every Encoding Each encoding is a Blossom blob identified by SHA-256. The track event carries one `audio` tag per encoding: hash, codec spec, server URL, MIME type, size. Downloading follows the existing Blossom/BUD flow; paid assets are gated by the signed access filter described in [FEATURES_ACCESS.md](./FEATURES_ACCESS.md). ### Track Event ```json { "kind": 32210, "pubkey": "", "content": "Liner notes, recording story, comments.", "tags": [ ["d", ""], ["title", "Song Title"], ["artist", "Band Name"], ["p", "", "wss://relay.musiquay.com", "performer"], ["a", "32211::", "wss://relay.musiquay.com"], ["album", "Album Name"], ["track", "5/12"], ["disc", "1/2"], ["duration", "247.32"], ["genre", "post-punk"], ["t", "postpunk"], ["release-date", "2026-06-15"], ["isrc", "PT-ABC-26-00001"], ["language", "en"], ["bpm", "138"], ["key", "Am"], ["copyright", "CC BY-NC-SA 4.0"], ["price", "500", "sat"], ["image", "", "https://blossom.musiquay.com"], ["i", "musicbrainz:recording:8be5c8c0-7b52-4a2d-9d4e-1c2f3a4b5c6d"], ["k", "musicbrainz:recording"], ["audio", "", "flac-24bit-96kHz", "https://blossom.musiquay.com", "audio/flac", "48216387"], ["audio", "", "mp3-128kbps-VBR", "https://blossom.musiquay.com", "audio/mpeg", "9110334"], ["audio", "", "opus-96kbps", "https://blossom.musiquay.com", "audio/ogg", "3942210"], ["x", ""], ["x", ""], ["x", ""], ["master", ""] ] } ``` **Design notes:** - **`d` tag** — the recording identifier. Random unique string by default; if the recording has an ISRC, the `d` tag SHOULD be the ISRC (same value as the `isrc` tag). ISRCs are globally unique per recording, so they make a stable, meaningful address. - **Author is publisher** — the pubkey of whoever took the master, encoded, and uploaded. Only this pubkey can replace the event. Artists are `p` tags; artist and publisher are often the same key but are not required to be. - **Replaceable** — every encoding addition, correction, or removal republishes the full tag set. New encodings arrive by replacement, so subscribers to the address always see the complete current encoding list. - **`master` tag** — points at the SHA-256 of the lossless/master encoding. Exactly one. Clients that offer transcoding, format migration, or archival work from the master. - **`x` tags** — one per encoding, mirroring the `audio` tags. Single-letter tags are the only ones relays index, so these are what make "which asset does this blob belong to?" a standard query: `{"kinds":[32210],"#x":[""]}`. Hosts need that answer to gate a download, and receipt issuers need it to name the asset in a deed. ### Audio Encoding Tags One `audio` tag per published encoding: ``` ["audio", "", "", "", "", ""] ``` | Field | Required | Notes | |-------|----------|-------| | sha256 | yes | Blob hash; the identity of the file on Blossom servers | | codec-spec | yes | Standard codec specification string, see vocabulary below | | server-url | recommended | Primary Blossom server hosting the blob. Omitted, clients fall back to the publisher's NIP-B7 kind 10063 server list | | media-type | recommended | MIME type, lowercase (NIP-94 `m` convention) | | size-bytes | optional | Blob size (NIP-94 `size` convention) | The codec specification string follows a fixed pattern so encodings are comparable, selectable, and renderable without parsing binaries: ``` [-kbps[-] | -bit-kHz | -q] ``` Examples from the standard vocabulary: | Encoding | codec-spec | media-type | |----------|-----------|------------| | MP3, V0 | `mp3-128kbps-VBR` | `audio/mpeg` | | MP3, 320 | `mp3-320kbps-CBR` | `audio/mpeg` | | AAC | `aac-256kbps-VBR` | `audio/mp4` | | Ogg Vorbis | `ogg-vorbis-q8` | `audio/ogg` | | Opus | `opus-96kbps` | `audio/ogg` | | FLAC 16-bit | `flac-16bit-44.1kHz` | `audio/flac` | | FLAC 24-bit | `flac-24bit-96kHz` | `audio/flac` | | WAV | `wav-24bit-48kHz` | `audio/wav` | | ALAC | `alac-16bit-44.1kHz` | `audio/mp4` | This is a convention, not a closed registry. New codecs and rates emerge simply by using new spec strings. The vocabulary guarantees the important property: **a client can always tell, from the tag alone, what kind of file it is about to download.** ### Metadata Tag Vocabulary Mapped against the standard tag annotations so existing libraries can import/export directly: | Tag | ID3 frame | MusicBrainz field | Notes | |-----|-----------|-------------------|-------| | `title` | TIT2 | Title | Track title | | `artist` | TPE1 | Artist credit | Free-text artist name; may repeat for multiple artists | | `p` | — | Artist | Artist npub, optional relay hint, role (`performer`, `featured`) | | `album` | TALB | Release title | Free-text, for display when the album event is absent | | `a` | — | Release | Address of the album event (kind 32211), when published | | `track` | TRCK | Track number | `"5"` or `"5/12"` | | `disc` | TPOS | Disc number | `"1"` or `"1/2"` | | `duration` | TLEN | Length | Seconds, floating point (NIP-71 convention) | | `genre` | TCON | Genre | Free-text; may repeat | | `t` | — | — | Hashtag form of genre for relay filtering and discovery | | `release-date` | TDRC | Date | ISO 8601 | | `isrc` | TSRC | ISRC | Recording identifier, uppercase | | `language` | TLAN | Language | ISO 639-1 | | `bpm` | TBPM | BPM | Integer | | `key` | TKEY | Key | Free-text | | `copyright` | TCOP | — | License string or SPDX identifier | | `price` | — | — | Minimum price for paid access: `["price", "", "sat"]`. Absent means free. See [FEATURES_ACCESS.md](./FEATURES_ACCESS.md). | | `image` | APIC | Cover art | `["image", "", ""]`, Blossom blob | | `i`/`k` | — | MBID | NIP-73 external IDs (see below) | | `content` | COMM | — | Liner notes, comments | Per-track credits (songwriters, session musicians, engineers) are **not** on the track event — they live on the [track credits event](./FEATURES_CREDITS.md) (kind 32215), which references this track by address. ### MusicBrainz and Other External IDs The `i`/`k` tags use NIP-73's external-content-ID mechanism. The MusicBrainz recording ID uses the convention `musicbrainz:recording:` — same pattern as the barcode IDs on [edition events](./FEATURES_CREDITS.md). NIP-73's supported-ID table does not yet list these; until the table is extended upstream, the convention works as-is because `i`/`k` values are open-ended. ## Album (Kind 32211) The album event is the **release identity**: title, artist, release date, artwork, and the ordered list of tracks. It is the anchor that [release credits](./FEATURES_CREDITS.md), [editions](./FEATURES_CREDITS.md), [merch listings](./FEATURES_MERCHANDISE.md), and [calendar release events](./FEATURES_CALENDAR.md) all reference. Published by the artist or label. Addressable, so track-list corrections, bonus tracks, and reissues replace the previous version. The track list is an ordered list of track addresses (`a` tags) — order is the track order, identical to MusicBrainz's release → medium → track position model. ```json { "kind": 32211, "pubkey": "", "content": "Release notes, album story.", "tags": [ ["d", ""], ["title", "Album Name"], ["artist", "Band Name"], ["p", "", "wss://relay.musiquay.com", "performer"], ["p", "", "wss://relay.musiquay.com", "label"], ["release-date", "2026-06-15"], ["genre", "post-punk"], ["t", "postpunk"], ["language", "en"], ["copyright", "CC BY-NC-SA 4.0"], ["price", "5000", "sat"], ["image", "", "https://blossom.musiquay.com"], ["i", "musicbrainz:release-group:5c9e6d6c-2c2e-4a7b-9c3f-3a4b5c6d7e8f"], ["k", "musicbrainz:release-group"], ["a", "32210::", "wss://relay.musiquay.com"], ["a", "32210::", "wss://relay.musiquay.com"], ["a", "32210::", "wss://relay.musiquay.com"] ] } ``` **Design notes:** - **Track order is tag order** — the sequence of `a` tags IS the tracklist. Clients render it in order; there is no separate position field. - **Multi-disc releases** — disc structure lives on the track events (`disc` tag, `"1/2"`); the album list is flat and ordered. - **Track events hold the audio** — the album event carries no encodings. Everything audio lives on the track events; the album is pure structure plus metadata. - **`d` tag** — arbitrary unique identifier; MusicBrainz release-group MBID recommended when available (via `i`/`k` tags in addition). - **Physical formats** — the album event is format-neutral. Vinyl/CD/cassette pressings are [edition events](./FEATURES_CREDITS.md) (kind 32216) that reference this album. ## Playlist (Kind 32212) Playlists are named, ordered collections of tracks, following NIP-51 set conventions: addressable event with `d`, `title`, `image`, `description` tags, and the members as `a` tags (track addresses) in order. This is the direct analog of NIP-51 video sets (kind 30005), applied to tracks. ```json { "kind": 32212, "pubkey": "", "content": "", "tags": [ ["d", "my-favourite-deep-cuts"], ["title", "My Favourite Deep Cuts"], ["description", "Tracks that never got the attention they deserved."], ["image", "", "https://blossom.musiquay.com"], ["a", "32210::", "wss://relay.musiquay.com"], ["a", "32210::", "wss://relay.musiquay.com"], ["a", "32210::", "wss://relay.musiquay.com"] ] } ``` **Design notes:** - **Public by default.** Private playlists encrypt the tag list into `.content` per NIP-51's private-list scheme (NIP-44, self-key). Shared-with-selected-pubkeys is a client concern — e.g. gift-wrapped copies via NIP-17. - **Replaceable** — reordering, adding, or removing tracks republishes the event. - **Curators can be anyone** — fans, artists, venues, labels. Playlists are part of the scene graph; a promoter's playlist becomes a discoverable object like any other. ## Play Reports (Kind 3221) Play reports are the **listener-side public signal** - the auditable counterpart to the private delivery receipts in [FEATURES_ACCESS.md](./FEATURES_ACCESS.md). A play report is a regular (immutable) event: one play, one record, never replaced. ```json { "kind": 3221, "pubkey": "", "content": "", "tags": [ ["a", "32210::", "wss://relay.musiquay.com"], ["p", ""], ["x", ""], ["server", "https://blossom.musiquay.com"], ["codec", "mp3-128kbps-VBR"], ["t0", "1758130000"], ["t1", "1758130247"], ["blind", ""], ["host", ""], ["statement", ""], ["dleq", "", ""] ] } ``` **Design notes:** - **Paid plays carry a blind signature** from the serving host, produced with Cashu's BDHKE (NUT-00). The statement is canonical and covers only what the host itself observed — `musiquay.play:v1||||` — because a host that blind-signs an arbitrary statement is a signing oracle. The host blinds `Y = hash_to_curve(statement)` without seeing the statement; the listener unblinds to `C = k*Y` and publishes `(statement, C, host, dleq)`. - **Verification uses the DLEQ proof, not `C == K*H(statement)`.** That equality is a pairing equation and secp256k1 has no pairing; the NUT-12 DLEQ proof `(e, s)` is what lets a third party verify `log_G(K) == log_Y(C)` without the host's key. A paid play report without `dleq` is not independently verifiable. - **`tier` and `amount` are not in the statement.** Money is accounted by delivery receipts and aggregates; leaving value fields out of the signed statement removes the incentive to forge one. Statement fields are joined by `|` and may not contain `|`. - **Free plays are self-attested** - no `blind`, `host`, or `statement` tags. Signal, not proof; useful for artists, easily gamed, treated accordingly. - **Never replaceable** - play counts are queried by counting events (NIP-45 `COUNT`), so immutability matters. A listener can NIP-09-delete their own report, but cannot edit it. - **`codec` tag** - which encoding was played, matching the track event's `audio` codec-spec. - **`x` tag** - the blob hash played, matching an `audio` tag on the track event. - **The live layer** - the social "now playing" signal is separate: NIP-38 kind 30315 status events with `d:music`, expiring when the track ends. Play reports are the record; NIP-38 statuses are the live feed. - **Aggregates** - public per-asset totals come from host aggregates (kind 32219) and publisher rollups (kind 32220), not from summing play reports. See [FEATURES_ACCESS.md](./FEATURES_ACCESS.md). ## Kind Number Block Musiquay's addressable kinds live in a contiguous block, 32210-32217. The regular kinds are 3221, 3222, 32218, 32219, and 32220 - they must be stored and counted, so they cannot be addressable, replaceable, or ephemeral. All are listed in [ARCHITECTURE.md](./ARCHITECTURE.md). | Kind | Name | Replaceability | |------|------|----------------| | 32210 | Track | Addressable | | 32211 | Album | Addressable | | 32212 | Playlist | Addressable | | 32213 | Setlist | Addressable | | 32214 | Release credits | Addressable | | 32215 | Track credits | Addressable | | 32216 | Edition | Addressable | | 32217 | Access filter | Addressable | | 3221 | Play report | Regular | | 3222 | Purchase order | Regular (private, NIP-59 only) | | 32218 | Delivery receipt | Regular | | 32219 | Host aggregate | Regular | | 32220 | Publisher rollup | Regular | The block and the regular kinds were re-checked free of collisions in the [registry of kinds](https://github.com/nostr-protocol/registry-of-kinds) on 2026-09-28. They should be registered there once implementation begins. ## NIP Strategy | Concept | NIP Status | Notes | |---------|------------|-------| | **Track event (32210)** | Custom kind | No existing NIP defines a recording; WaveLake 32123 is dead prior art with no spec. | | **Album event (32211)** | Custom kind | No existing NIP defines a release. | | **Playlist (32212)** | Custom kind, NIP-51 set conventions | Addressable with `d`/`title`/`image`/`description`; analog of kind 30005 video sets. | | **Play report (3221)** | Custom kind | Listener-side signal; BDHKE blind signature certifies paid plays. | | **Access filter (32217)** | Custom kind | Signed probabilistic access set; see [FEATURES_ACCESS.md](./FEATURES_ACCESS.md). | | **Delivery receipt (32218)** | Custom kind, NIP-59 | Private host-signed deed. | | **Host aggregate (32219)** | Custom kind | Public host-signed totals. | | **Publisher rollup (32220)** | Custom kind | Public publisher-signed consolidation referencing 32219 events. | | **Replaceable semantics** | NIP-01 | Parameterized replaceable kinds (30000-39999), `d` tag | | **Blob identity** | NIP-94 conventions | `x` sha256, `m` MIME, `size`; one single-letter `x` tag per encoding so blob → asset is a `#x` query | | **Blossom servers** | NIP-B7 | Server fallback via publisher's kind 10063 list when `server-url` omitted | | **Media authorization** | BUD-11 | Signed kind 24242 presented as `Authorization: Nostr `; this is how a host identifies a requester | | **Duration** | NIP-71 convention | Seconds, floating point | | **External IDs** | NIP-73 | `i`/`k` for ISRC, MusicBrainz recording/release-group IDs | | **Paid access** | Custom filters + NUT-24/BUD-07 + NUT-00 BDHKE | See [FEATURES_ACCESS.md](./FEATURES_ACCESS.md) | | **Addressing** | NIP-19 | `naddr` codes for sharing | | **Live now-playing** | NIP-38 | kind 30315 `d:music` status, the social companion to play reports |