clone

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

main
nip.guide / site / nips / 40.html
40.html 16.9K
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-40 - Expiration Timestamp — Nostr Instruction Manual</title>7<meta name="description" content="NIP-40: the expiration tag. Mark an event with a unix timestamp so relays and clients treat it as expired. 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 40 - Relay Ops</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="40">40</div>48 <div class="titles">49 <div class="kicker">Nostr Implementation Possibility - Hex № 40</div>50 <h1>Expiration Timestamp</h1>51 <p class="sub">One tag gives an event a best-before date. After that moment, relays hide it and clients ignore it.</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>Events on Nostr live forever by default. A relay stores a regular event and serves it to anyone who asks. Some content should not live forever. A flash sale ends. A meetup announcement goes stale. This NIP adds a self-destruct timer for such events.</p>60 <p>The tool is one tag: <code>expiration</code>. The tag holds a unix timestamp in seconds. The timestamp marks the moment when the event SHOULD be considered expired. Relays and clients both apply this rule. Relays SHOULD delete the event at or after that moment.</p>61 <p>Support is optional. A relay advertises support in its <a href="11.html">NIP-11</a> information document. A client checks that document before it publishes an expiring event.</p>6263 <div class="box warn">64 <span class="tag">Warning!</span>65 <p>Expiration is a housekeeping hint, not a security feature. The event is public on every relay until deletion. Any third party can download and keep a copy before it expires. Do not use this tag to protect conversations or secrets.</p>66 </div>6768 <figure class="diagram">69 <div class="frame">70 <svg viewBox="0 0 560 150" role="img" aria-label="Timeline of an expiring event: created, served while fresh, expired at the timestamp, then deleted by the relay">71 <line class="d-wire" x1="20" y1="90" x2="540" y2="90"/>72 <circle cx="70" cy="90" r="5" fill="#2e5f9e"/>73 <text class="d-label" x="70" y="72" text-anchor="middle">created_at</text>74 <text class="d-note" x="70" y="115" text-anchor="middle">client publishes</text>75 <rect x="90" y="82" width="230" height="16" rx="4" fill="#2c7a3f" opacity="0.35"/>76 <text class="d-note" x="205" y="60" text-anchor="middle">fresh — relay stores and serves the event</text>77 <circle cx="340" cy="90" r="5" fill="#f26a00"/>78 <text class="d-label" x="340" y="72" text-anchor="middle">expiration</text>79 <text class="d-note" x="340" y="115" text-anchor="middle">SHOULD be deleted</text>80 <path class="d-msg d-flow" d="M360,90 L520,90"/>81 <text class="d-note" x="445" y="60" text-anchor="middle">expired — hidden from clients, deletion may lag</text>82 <circle r="4" fill="#f26a00">83 <animateMotion dur="2.6s" repeatCount="indefinite" path="M360,90 L520,90"/>84 </circle>85 </svg>86 </div>87 <figcaption>Fig. 40-1 — <b>Event lifetime.</b> The event is normal until the <code>expiration</code> moment. After it, relays stop serving the event and delete it when they can.</figcaption>88 </figure>8990 <h2 class="bar" id="spec"><span class="num">2</span> The expiration Tag</h2>91 <p>Add one <code>expiration</code> tag to the <code>tags</code> array of any event. The tag has one value. The value is a unix timestamp in seconds, written as a string. The value is required.</p>9293 <div class="crt">94 <div class="titlebar">Tag format - expiration</div>95<pre><span class="k">tag</span>: expiration96<span class="k">values</span>:97 - [<span class="c">UNIX timestamp in seconds</span>]: <span class="s">required</span></pre>98 </div>99100 <div class="tscroll"><table class="ref">101 <caption>Tag reference</caption>102 <tr><th>Tag</th><th>Value</th><th>Rule</th></tr>103 <tr><td class="btn">expiration</td><td>unix timestamp, seconds, as a string</td><td>Required value. Marks the moment when the event SHOULD be considered expired and SHOULD be deleted by relays.</td></tr>104 </table></div>105106 <p>The timestamp uses the same format as the <code>created_at</code> field from <a href="01.html">NIP-01</a>: seconds since the unix epoch. Interpret it as the time at which relays should delete the event.</p>107108 <div class="crt">109 <div class="titlebar">Example - expiring event</div>110<pre>{111 <span class="k">"pubkey"</span>: <span class="c">&lt;pub-key&gt;</span>,112 <span class="k">"created_at"</span>: 1000000000,113 <span class="k">"kind"</span>: 1,114 <span class="k">"tags"</span>: [115 [<span class="s">"expiration"</span>, <span class="s">"1600000000"</span>]116 ],117 <span class="k">"content"</span>: <span class="s">"This message will expire at the specified timestamp and be deleted by relays.\n"</span>,118 <span class="k">"id"</span>: <span class="c">&lt;event-id&gt;</span>119}</pre>120 </div>121122 <div class="box hint">123 <span class="tag">Hint!</span>124 <p>The tag value is a string, like every tag value in Nostr. Write <code>"1600000000"</code>, with quotes. The <code>created_at</code> field next to it is a bare integer. Do not mix the two forms up.</p>125 </div>126127 <h2 class="bar" id="client"><span class="num">3</span> Client Behavior</h2>128 <p>Not every relay implements this NIP. A relay that does lists the number <code>40</code> in the <code>supported_nips</code> field of its <a href="11.html">NIP-11</a> information document. Clients SHOULD use that field to learn if a relay supports this NIP.</p>129 <ul>130 <li>Clients SHOULD NOT send expiration events to relays that do not support this NIP.</li>131 <li>Clients SHOULD ignore events that have expired. Apply this rule even when a relay still delivers an expired event.</li>132 </ul>133134 <h2 class="bar" id="relay"><span class="num">4</span> Relay Behavior</h2>135 <p>A relay that supports this NIP applies four rules:</p>136 <ul>137 <li>The relay is not required to delete an expired event at the exact expiration moment. It may delete late, and it may persist the event indefinitely.</li>138 <li>The relay SHOULD NOT send expired events to clients, even if it still stores them.</li>139 <li>The relay SHOULD drop any event that is already expired when a client publishes it.</li>140 <li>An expiration timestamp does not affect the storage of ephemeral events. Ephemeral kinds (see <a href="01.html">NIP-01</a>) are not stored anyway.</li>141 </ul>142143 <div class="box tech">144 <span class="tag">Tech Note</span>145 <p>The source spec writes "Relays MAY NOT delete expired messages immediately". "MAY NOT" is not an RFC 2119 keyword, and it can read as a prohibition. The next clause ("and MAY persist them indefinitely") shows the intent: deletion is permitted but not required to be immediate. This page restates that intent.</p>146 </div>147148 <figure class="diagram">149 <div class="frame">150 <svg viewBox="0 0 560 300" role="img" aria-label="Sequence diagram: client checks supported_nips, publishes an expiring event, relay accepts it; after expiry a REQ does not return the event">151 <line class="d-wire" x1="110" y1="40" x2="110" y2="285" stroke-dasharray="3 4"/>152 <line class="d-wire" x1="450" y1="40" x2="450" y2="285" stroke-dasharray="3 4"/>153 <rect class="d-actor" x="55" y="8" width="110" height="30" rx="6"/>154 <text class="d-actor-label" x="110" y="28" text-anchor="middle">Client</text>155 <rect class="d-actor" x="395" y="8" width="110" height="30" rx="6"/>156 <text class="d-actor-label" x="450" y="28" text-anchor="middle">Relay</text>157 <path class="d-msg" d="M110,62 L445,62"/>158 <text class="d-label" x="280" y="55" text-anchor="middle">NIP-11 request: is 40 in supported_nips?</text>159 <path class="d-msg blue" d="M450,95 L115,95"/>160 <text class="d-label" x="280" y="88" text-anchor="middle">{"supported_nips": [1, 11, 40, …]}</text>161 <path class="d-msg" d="M110,128 L445,128"/>162 <text class="d-label" x="280" y="121" text-anchor="middle">["EVENT", {…, "tags":[["expiration","1600000000"]]}]</text>163 <path class="d-msg blue" d="M450,161 L115,161"/>164 <text class="d-label" x="280" y="154" text-anchor="middle">["OK", &lt;id&gt;, true, ""]</text>165 <path class="d-msg d-flow" d="M110,215 L445,215"/>166 <text class="d-label" x="280" y="208" text-anchor="middle">later, after expiry: ["REQ", "sub1", {…}]</text>167 <path class="d-msg blue" d="M450,248 L115,248"/>168 <text class="d-label" x="280" y="241" text-anchor="middle">["EOSE", "sub1"] — expired event not sent</text>169 <text class="d-note" x="280" y="278" text-anchor="middle">The relay hides the expired event and deletes it on its own schedule.</text>170 </svg>171 </div>172 <figcaption>Fig. 40-2 — <b>Expiration flow.</b> The client checks support first, then publishes. After the timestamp, the relay stops serving the event.</figcaption>173 </figure>174175 <h2 class="bar" id="usecases"><span class="num">5</span> Suggested Use Cases</h2>176 <ul>177 <li><strong>Temporary announcements.</strong> An event organizer posts announcements about an upcoming event. The posts expire when the announcement is no longer useful.</li>178 <li><strong>Limited-time offers.</strong> A business posts a special offer that is only available for a limited time. The offer expires after that time.</li>179 </ul>180181 <h2 class="bar" id="examples"><span class="num">6</span> Worked Example</h2>182 <p>A cafe posts a lunch offer at 12:00 that expires at 15:00 the same day. The session below shows the publish, a fresh read, and a read after expiry. Orange lines go to the relay. Blue lines come from the relay.</p>183 <div class="crt">184 <div class="titlebar">Session transcript - wss://relay.example.com</div>185<pre><span class="c">-- 12:00 - the cafe publishes an offer that expires at 15:00 --</span>186<span class="send">→ ["EVENT", {"id":"7d1e02fa…","pubkey":"ac93be21…","created_at":1749812400,187 "kind":1,"tags":[["expiration","1749823200"]],188 "content":"Lunch special: soup + coffee, until 15:00 today!","sig":"91cc04d7…"}]</span>189<span class="recv">← ["OK", "7d1e02fa…", true, ""]</span>190191<span class="c">-- 13:30 - a customer reads the feed; the offer is still fresh --</span>192<span class="send">→ ["REQ", "menu", {"kinds":[1], "authors":["ac93be21…"]}]</span>193<span class="recv">← ["EVENT", "menu", {"id":"7d1e02fa…", "content":"Lunch special: …", …}]</span>194<span class="recv">← ["EOSE", "menu"]</span>195<span class="send">→ ["CLOSE", "menu"]</span>196197<span class="c">-- 16:00 - after expiry, the relay no longer serves the event --</span>198<span class="send">→ ["REQ", "menu2", {"kinds":[1], "authors":["ac93be21…"]}]</span>199<span class="recv">← ["EOSE", "menu2"]</span>200201<span class="c">-- publishing an already-expired event gets dropped --</span>202<span class="send">→ ["EVENT", {"id":"e4b09cd2…", "tags":[["expiration","1600000000"]], …}]</span>203<span class="recv">← ["OK", "e4b09cd2…", false, "invalid: event is expired"]</span></pre>204 </div>205 <p>A careful client also ignores expired events on its own. If a lagging relay still delivers the offer at 16:00, the client compares the tag value with the current time and hides the event.</p>206207 <h2 class="bar" id="history"><span class="num">7</span> Version History</h2>208 <p>NIP-40 arrived in December 2022 and has changed little since. Notable changes, newest first:</p>209 <ul class="patchnotes">210 <li><span class="ver">2025</span><span class="when">2025-12</span>Added the <code>relay</code> tag to the preamble, marking the NIP as one that relays implement.</li>211 <li><span class="ver">2023</span><span class="when">2023-11</span>fiatjaf reformatted the JSON example and removed the listed NIP authors, as part of a repo-wide cleanup.</li>212 <li class="minor"><span class="ver">2023</span><span class="when">2023-04</span>Grammar and typo fixes.</li>213 <li><span class="ver">2022</span><span class="when">2022-12</span>A rapid series of edits filled in the spec: client behavior via <code>supported_nips</code>, relay deletion rules, the ephemeral-event carve-out, use cases, and the privacy warning.</li>214 <li><span class="ver">2022</span><span class="when">2022-12</span>The tag value was fixed as a UNIX timestamp in seconds.</li>215 <li><span class="ver">Origin</span><span class="when">2022-12-04</span>Thomas created <code>40.md</code> with the expiration tag proposal.</li>216 </ul>217218 <div class="credits">219 <h3 class="cardhead">Original Proposal - Credits</h3>220 <table>221 <tr><td>Author</td><td>Thomas</td></tr>222 <tr><td>First commit</td><td>2022-12-04 — “Create 40.md”</td></tr>223 <tr><td>Status</td><td>draft - optional - relay — relays advertise support via <a href="11.html">NIP-11</a></td></tr>224 <tr><td>Source</td><td><a href="https://github.com/nostr-protocol/nips/blob/master/40.md">40.md on GitHub</a> - <a href="https://github.com/nostr-protocol/nips/commits/master/40.md">full change history</a></td></tr>225 </table>226 </div>227228 <h2 class="bar"><span class="num">8</span> See Also</h2>229 <ul>230 <li><a href="01.html">NIP-01</a> — defines the event object, the <code>created_at</code> timestamp format, and ephemeral kinds.</li>231 <li><a href="11.html">NIP-11</a> — the relay information document with the <code>supported_nips</code> field that clients check.</li>232 <li><a href="09.html">NIP-09</a> — deletion requests; the author asks for removal instead of scheduling it in advance.</li>233 </ul>234 </div>235236 <aside>237 <div class="cartridge">238 <div class="inner">239 <h3 class="cardhead">Spec Card</h3>240 <div class="lights"><span class="led on"></span><span class="led on"></span><span class="led on"></span></div>241 <dl>242 <dt>Status</dt><dd><span class="chip draft">draft</span><span class="chip">optional</span><span class="chip">relay</span></dd>243 <dt>Defines</dt><dd><code>expiration</code> tag</dd>244 <dt>Kind(s)</dt><dd>none — the tag works on any kind</dd>245 <dt>Requires</dt><dd><a href="01.html">NIP-01</a> - <a href="11.html">NIP-11</a> for discovery</dd>246 <dt>Transport</dt><dd>WebSocket - JSON arrays</dd>247 <dt>First commit</dt><dd>2022-12-04</dd>248 <dt>Last updated</dt><dd>2025-12-24</dd>249 </dl>250 </div>251 </div>252 </aside>253 </main>254255 <nav class="navbtns">256 <a href="39.html">◀ NIP-39: Linking Profiles to Other Platforms</a>257 <a href="42.html">NIP-42: Authentication of clients to relays ▶</a>258 </nav>259260 <footer class="pagefoot">261 <a href="../index.html">Nostr Protocol Manual</a>262 <span class="pageno">NIP 40 / F4</span>263 </footer>264</div>265266<script src="../assets/webmcp.js" defer></script>267</body>268</html>