clone

every nostr nip as a chapter of an illustrated, early-2000s printed game manual

main
nip.guide / site / nips / a0.html
a0.html 18.0K
1<!DOCTYPE html>2<html lang="en">3<head>4<meta charset="utf-8">5<meta name="viewport" content="width=device-width, initial-scale=1">6<title>NIP-A0 - Voice Messages — Nostr Instruction Manual</title>7<meta name="description" content="NIP-A0: short voice messages on Nostr. Kind 1222 root audio posts, kind 1244 audio replies, and imeta waveform previews. Complete manual page.">8<link rel="preload" href="../assets/fonts/michroma-400-latin.woff2" as="font" type="font/woff2" crossorigin>9<link rel="preload" href="../assets/fonts/exo2-var-latin.woff2" as="font" type="font/woff2" crossorigin>10<link rel="preload" href="../assets/fonts/sairacondensed-600-latin.woff2" as="font" type="font/woff2" crossorigin>11<link rel="preload" href="../assets/fonts/sairacondensed-700-latin.woff2" as="font" type="font/woff2" crossorigin>12<link rel="preload" href="../assets/fonts/sairacondensed-500-latin.woff2" as="font" type="font/woff2" crossorigin>13<link rel="preload" href="../assets/fonts/sharetechmono-400-latin.woff2" as="font" type="font/woff2" crossorigin>14<link rel="preload" href="../assets/fonts/exo2-400i-latin.woff2" as="font" type="font/woff2" crossorigin>15<link rel="icon" href="../assets/favicon.svg" type="image/svg+xml">16<link rel="stylesheet" href="../assets/manual.css">17</head>18<body>1920<svg width="0" height="0" style="position:absolute">21 <defs>22 <marker id="arr" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto">23 <path d="M1,1 L8,4.5 L1,8 Z" fill="#f26a00"/>24 </marker>25 <marker id="arrb" markerWidth="9" markerHeight="9" refX="7" refY="4.5" orient="auto">26 <path d="M1,1 L8,4.5 L1,8 Z" fill="#2e5f9e"/>27 </marker>28 </defs>29</svg>3031<div class="page">32 <span class="staple s1"></span><span class="staple s2"></span>3334 <header class="band">35 <a class="logo" href="../index.html">NOSTR<b>▸</b>PROTOCOL MANUAL</a>36 <span class="booklet-note">Chapter A0 - Media</span>37 </header>38 <nav class="tabs">39 <a href="../index.html">Contents</a>40 <a href="#overview" class="on">Overview</a>41 <a href="#spec">Spec</a>42 <a href="#examples">Examples</a>43 <a href="#history">History</a>44 </nav>4546 <div class="chapter">47 <div class="nipno" data-n="A0">A0</div>48 <div class="titles">49 <div class="kicker">Nostr Implementation Possibility - Hex № A0</div>50 <h1>Voice Messages</h1>51 <p class="sub">Short audio posts and audio replies: kind 1222 for root voice messages, kind 1244 for voice replies, with an optional waveform preview.</p>52 </div>53 </div>5455 <main class="spread">56 <div class="main">5758 <h2 class="bar" id="overview"><span class="num">1</span> Overview</h2>59 <p>Some things are easier to say than to type. This NIP defines a voice message: a short audio clip, typically up to 60 seconds long, published as a Nostr event. It gives voice posts their own kinds, so audio feeds do not mix with kind-1 text notes.</p>60 <p>The NIP defines two event kinds. <strong>Kind 1222</strong> is a root voice message. It starts a thread. <strong>Kind 1244</strong> is a voice reply. It answers a root message or another reply, and follows the comment structure of <a href="22.html">NIP-22</a>.</p>61 <p>The audio itself does not live inside the event. The event <code>content</code> is a URL that points directly to an audio file on a media server. Clients download or stream the file from that URL. An optional <code>imeta</code> tag from <a href="92.html">NIP-92</a> carries a waveform and a duration, so clients can draw a preview before they fetch any audio.</p>6263 <div class="box hint">64 <span class="tag">Hint!</span>65 <p>Think walkie-talkie, not podcast. The 60-second target keeps voice feeds fast to scan and cheap to host. For long-form audio or video, look at other media NIPs such as <a href="71.html">NIP-71</a>.</p>66 </div>6768 <figure class="diagram">69 <div class="frame">70 <svg viewBox="0 0 560 190" role="img" aria-label="Recorder uploads audio to a media server, publishes a kind 1222 event to a relay, and a listener fetches the event and streams the audio">71 <rect class="d-actor" x="10" y="70" width="110" height="50" rx="8"/>72 <text class="d-actor-label" x="65" y="93" text-anchor="middle">Recorder</text>73 <text class="d-note" x="65" y="110" text-anchor="middle">client A</text>74 <rect class="d-actor" x="225" y="20" width="110" height="44" rx="8"/>75 <text class="d-actor-label" x="280" y="41" text-anchor="middle">Media server</text>76 <text class="d-note" x="280" y="56" text-anchor="middle">hosts the .m4a</text>77 <rect class="d-actor" x="225" y="126" width="110" height="44" rx="8"/>78 <text class="d-actor-label" x="280" y="153" text-anchor="middle">Relay</text>79 <rect class="d-actor" x="440" y="70" width="110" height="50" rx="8"/>80 <text class="d-actor-label" x="495" y="93" text-anchor="middle">Listener</text>81 <text class="d-note" x="495" y="110" text-anchor="middle">client B</text>82 <path class="d-msg d-flow" d="M122,84 C170,70 180,52 223,44"/>83 <path class="d-msg d-flow" d="M122,106 C170,120 180,138 223,146"/>84 <path class="d-msg blue d-flow" d="M337,146 C380,138 390,120 438,106"/>85 <path class="d-msg blue d-flow" d="M337,44 C380,52 390,70 438,84"/>86 <text class="d-label" x="160" y="48" text-anchor="middle">1. upload audio</text>87 <text class="d-label" x="160" y="150" text-anchor="middle">2. EVENT 1222</text>88 <text class="d-label" x="400" y="150" text-anchor="middle">3. REQ / EVENT</text>89 <text class="d-label" x="400" y="48" text-anchor="middle">4. stream audio</text>90 <circle r="4" fill="#f26a00">91 <animateMotion dur="2.6s" repeatCount="indefinite" path="M122,106 C170,120 180,138 223,146"/>92 </circle>93 <circle r="4" fill="#2e5f9e">94 <animateMotion dur="2.6s" begin="1.3s" repeatCount="indefinite" path="M337,146 C380,138 390,120 438,106"/>95 </circle>96 </svg>97 </div>98 <figcaption>Fig. A0-1 — <b>Voice message flow.</b> The audio file goes to a media server. The event carries only the URL.</figcaption>99 </figure>100101 <h2 class="bar" id="spec"><span class="num">2</span> Root Voice Messages: Kind 1222</h2>102 <p>A kind 1222 event is a standalone voice post. It is a regular event under the <a href="01.html">NIP-01</a> storage rules. Its fields follow these rules:</p>103104 <div class="tscroll"><table class="ref">105 <caption>Kind 1222 - field rules</caption>106 <tr><th>Field</th><th>Requirement</th><th>Rule</th></tr>107 <tr><td class="btn">content</td><td>MUST</td><td>A URL that points directly to an audio file. No text, no markup, only the URL.</td></tr>108 <tr><td class="btn">tags</td><td>MAY</td><td>Tags from other NIPs are allowed. Examples: <code>t</code> for hashtags, <code>g</code> for a geohash.</td></tr>109 </table></div>110111 <p>The audio file itself has two SHOULD rules:</p>112 <ul>113 <li><strong>Format.</strong> The file SHOULD be <code>audio/mp4</code> (<code>.m4a</code>) with AAC or Opus encoding. Clients MAY support other common formats such as <code>audio/ogg</code>, <code>audio/webm</code>, or <code>audio/mpeg</code> (mp3). The spec recommends <code>audio/mp4</code> for broad compatibility and efficiency.</li>114 <li><strong>Duration.</strong> The audio SHOULD be no longer than 60 seconds. A publishing client SHOULD enforce this limit, or show the user a clear warning when the recording exceeds it.</li>115 </ul>116117 <div class="box warn">118 <span class="tag">Warning!</span>119 <p>The event does not contain the audio. If the media server deletes the file, the voice message goes silent, even though the event still verifies. Choose durable hosting, or mirror the file on several servers.</p>120 </div>121122 <h2 class="bar"><span class="num">3</span> Voice Replies: Kind 1244</h2>123 <p>A kind 1244 event is a voice reply. Its <code>content</code> and audio rules are identical to kind 1222:</p>124 <ul>125 <li><code>content</code> MUST be a URL that points directly to an audio file.</li>126 <li>The file SHOULD be <code>audio/mp4</code> (<code>.m4a</code>) with AAC or Opus encoding; clients MAY support <code>audio/ogg</code>, <code>audio/webm</code>, or <code>audio/mpeg</code>.</li>127 <li>The audio SHOULD be no longer than 60 seconds; enforce the limit or warn the user.</li>128 <li>Tags from other NIPs MAY be included, such as <code>t</code> and <code>g</code>.</li>129 </ul>130 <p>One rule is extra: a kind 1244 event MUST follow the threading structure of <a href="22.html">NIP-22</a>. Uppercase tags (<code>E</code>, <code>K</code>, <code>P</code>) point to the root voice message. Lowercase tags (<code>e</code>, <code>k</code>, <code>p</code>) point to the direct parent. In a top-level reply, root and parent are the same event.</p>131132 <figure class="diagram">133 <div class="frame">134 <svg viewBox="0 0 560 200" role="img" aria-label="Thread structure: a kind 1222 root with two kind 1244 replies; a nested reply points to the root with uppercase tags and to its parent with lowercase tags">135 <rect class="d-actor" x="10" y="20" width="150" height="46" rx="8"/>136 <text class="d-actor-label" x="85" y="41" text-anchor="middle">kind 1222</text>137 <text class="d-note" x="85" y="57" text-anchor="middle">root voice message</text>138 <rect class="d-actor" x="220" y="20" width="150" height="46" rx="8"/>139 <text class="d-actor-label" x="295" y="41" text-anchor="middle">kind 1244</text>140 <text class="d-note" x="295" y="57" text-anchor="middle">reply to root</text>141 <rect class="d-actor" x="400" y="130" width="150" height="46" rx="8"/>142 <text class="d-actor-label" x="475" y="151" text-anchor="middle">kind 1244</text>143 <text class="d-note" x="475" y="167" text-anchor="middle">reply to a reply</text>144 <path class="d-msg" d="M218,43 L164,43"/>145 <text class="d-label" x="191" y="34" text-anchor="middle">E K P + e k p</text>146 <path class="d-msg" d="M448,128 C400,90 340,72 300,68"/>147 <text class="d-label" x="392" y="88" text-anchor="middle">e k p → parent</text>148 <path class="d-msg blue" d="M400,153 C240,150 110,110 82,70"/>149 <text class="d-label" x="220" y="140" text-anchor="middle">E K P → root</text>150 </svg>151 </div>152 <figcaption>Fig. A0-2 — <b>Thread structure per <a href="22.html">NIP-22</a>.</b> Uppercase tags always point to the root; lowercase tags point to the direct parent.</figcaption>153 </figure>154155 <div class="box tech">156 <span class="tag">Tech Note</span>157 <p>The source spec has a copy-paste slip: in the kind 1244 section, the duration rule says clients publishing <code>kind: 1222</code> events should enforce the limit. In context the rule clearly targets kind 1244. Also, the spec shows only a root example; it defines no separate reply example.</p>158 </div>159160 <h2 class="bar"><span class="num">4</span> Visual Preview with imeta</h2>161 <p>Downloading audio just to draw a feed is wasteful. The event MAY carry an <code>imeta</code> tag from <a href="92.html">NIP-92</a>, so clients can render a visual preview without fetching the audio file first. Two <code>imeta</code> entries matter here:</p>162163 <div class="tscroll"><table class="ref">164 <caption>imeta entries for voice messages (optional)</caption>165 <tr><th>Entry</th><th>Value</th><th>Purpose</th></tr>166 <tr><td class="btn">waveform</td><td>space-separated whole integers</td><td>Amplitude values over time. Fewer than 100 values is enough for a nice visual.</td></tr>167 <tr><td class="btn">duration</td><td>integer, seconds</td><td>The audio length. Lets the client show a play time before download.</td></tr>168 </table></div>169170 <div class="box hint">171 <span class="tag">Hint!</span>172 <p>Sample the waveform on the recording device, where the raw audio is already in memory. Normalize the values to a fixed range such as 0-100. The listener's client only scales bars; it never decodes audio for the preview.</p>173 </div>174175 <h2 class="bar" id="examples"><span class="num">5</span> Worked Example</h2>176 <p>A real root voice message, taken from the spec. The <code>content</code> URL points to an 8-second clip on a media server. The <code>imeta</code> tag repeats the URL and adds the waveform and duration:</p>177178 <div class="crt">179 <div class="titlebar">Event - kind 1222 root voice message</div>180<pre>{181 <span class="k">"content"</span>: <span class="s">"https://blossom.primal.net/5fe7df0e46ee6b14b5a8b8b929182 39e84e3ca5e3950eb630299742325d5ed9891b.mp4"</span>,183 <span class="k">"created_at"</span>: 1752501052,184 <span class="k">"id"</span>: <span class="c">"..."</span>,185 <span class="k">"kind"</span>: 1222,186 <span class="k">"pubkey"</span>: <span class="c">"..."</span>,187 <span class="k">"sig"</span>: <span class="c">"..."</span>,188 <span class="k">"tags"</span>: [189 [190 <span class="s">"imeta"</span>,191 <span class="s">"url https://blossom.primal.net/5fe7df0e46ee6b14b5a8b8b929192 39e84e3ca5e3950eb630299742325d5ed9891b.mp4"</span>,193 <span class="s">"waveform 0 7 35 8 100 100 49 8 4 16 8 10 7 2 20 10 100 100194 100 100 100 100 15 100 100 100 25 60 5 4 3 1 0 100 100 15195 100 29 88 0 33 11 39 100 100 19 4 100 42 35 5 0 1 5 0 0 11196 38 100 94 17 11 44 58 5 100 100 100 55 14 72 100 100 57 6197 1 14 2 16 100 100 40 16 100 100 6 32 14 13 41 36 16 14 6 3198 0 1 2 1 6 0"</span>,199 <span class="s">"duration 8"</span>200 ]201 ]202}</pre>203 </div>204205 <p>A voice reply answers that message with a kind 1244 event. The tags follow <a href="22.html">NIP-22</a>. Here the reply targets the root directly, so the uppercase and lowercase tags point to the same event:</p>206207 <div class="crt">208 <div class="titlebar">Session transcript - publishing a voice reply</div>209<pre><span class="c">-- Client B replies to root event a0f1c2... by pubkey 22a12a12... --</span>210<span class="send">→ ["EVENT", {"kind":1244,211 "content":"https://media.example.com/reply-clip.m4a",212 "tags":[213 ["E", "a0f1c2...", "wss://relay.example.com", "22a12a12..."],214 ["K", "1222"],215 ["P", "22a12a12..."],216 ["e", "a0f1c2...", "wss://relay.example.com", "22a12a12..."],217 ["k", "1222"],218 ["p", "22a12a12..."],219 ["imeta", "url https://media.example.com/reply-clip.m4a",220 "waveform 0 12 40 88 60 22 5", "duration 6"]221 ],222 "created_at":1752501300, "id":"b7d3e4...", "pubkey":"f7234bd4...",223 "sig":"..."}]</span>224<span class="recv">← ["OK", "b7d3e4...", true, ""]</span></pre>225 </div>226227 <h2 class="bar" id="history"><span class="num">6</span> Version History</h2>228 <p>NIP-A0 is young and small. Its whole history is two commits, days apart:</p>229 <ul class="patchnotes">230 <li><span class="ver">2025</span><span class="when">2025-07-27</span>Updated the audio format and waveform recommendations: <code>audio/mp4</code> with AAC or Opus became the recommended format (<a href="https://github.com/nostr-protocol/nips/pull/1990">#1990</a>).</li>231 <li><span class="ver">Origin</span><span class="when">2025-07-23</span>Fabian published the initial spec: kinds 1222 and 1244, the 60-second guideline, and the <code>imeta</code> preview entries (<a href="https://github.com/nostr-protocol/nips/pull/1984">#1984</a>).</li>232 </ul>233234 <div class="credits">235 <h3 class="cardhead">Original Proposal - Credits</h3>236 <table>237 <tr><td>Author</td><td>Fabian</td></tr>238 <tr><td>First commit</td><td>2025-07-23 — “NIP-A0: Voice Messages” (<a href="https://github.com/nostr-protocol/nips/pull/1984">PR #1984</a>)</td></tr>239 <tr><td>Status</td><td>draft — optional media feature for clients</td></tr>240 <tr><td>Source</td><td><a href="https://github.com/nostr-protocol/nips/blob/master/A0.md">A0.md on GitHub</a> - <a href="https://github.com/nostr-protocol/nips/commits/master/A0.md">full change history</a></td></tr>241 </table>242 </div>243244 <h2 class="bar"><span class="num">7</span> See Also</h2>245 <ul>246 <li><a href="01.html">NIP-01</a> — the base event format and client-relay flow that kinds 1222 and 1244 ride on.</li>247 <li><a href="22.html">NIP-22</a> — the comment structure that kind 1244 replies must follow.</li>248 <li><a href="92.html">NIP-92</a> — the <code>imeta</code> tag that carries the waveform and duration preview.</li>249 <li><a href="94.html">NIP-94</a> — file metadata events for describing hosted media in more detail.</li>250 <li><a href="71.html">NIP-71</a> — video events; the long-form cousin of voice messages.</li>251 </ul>252 </div>253254 <aside>255 <div class="cartridge">256 <div class="inner">257 <h3 class="cardhead">Spec Card</h3>258 <div class="lights"><span class="led on"></span><span class="led on"></span><span class="led on"></span></div>259 <dl>260 <dt>Status</dt><dd><span class="chip draft">draft</span></dd>261 <dt>Defines</dt><dd>kind 1222 root voice message - kind 1244 voice reply</dd>262 <dt>Kinds</dt><dd>1222, 1244</dd>263 <dt>Requires</dt><dd><a href="01.html">NIP-01</a> - <a href="22.html">NIP-22</a> for replies - <a href="92.html">NIP-92</a> optional</dd>264 <dt>Media</dt><dd>audio/mp4 (.m4a), AAC or Opus - ≤ 60 s</dd>265 <dt>First commit</dt><dd>2025-07-23</dd>266 <dt>Last updated</dt><dd>2025-07-27</dd>267 </dl>268 </div>269 </div>270 </aside>271 </main>272273 <nav class="navbtns">274 <a href="99.html">◀ NIP-99: Classified Listings</a>275 <a href="a3.html">NIP-A3: payto: Payment Targets ▶</a>276 </nav>277278 <footer class="pagefoot">279 <a href="../index.html">Nostr Protocol Manual</a>280 <span class="pageno">NIP A0 / F4</span>281 </footer>282</div>283284<script src="../assets/webmcp.js" defer></script>285</body>286</html>