clone

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

main
nip.guide / site / nips / 52.html
52.html 34.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-52 - Calendar Events — Nostr Instruction Manual</title>7<meta name="description" content="NIP-52: calendar events on Nostr. Date-based and time-based events, calendars, RSVPs, and every tag they use. 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 52 - Scheduling</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="52">52</div>48 <div class="titles">49 <div class="kicker">Nostr Implementation Possibility - Hex № 52</div>50 <h1>Calendar Events</h1>51 <p class="sub">Date-based and time-based calendar events, the calendars that collect them, and the RSVPs that answer them — all as addressable Nostr events.</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>This NIP puts calendars on Nostr. A <strong>calendar event</strong> is an occurrence at a specific moment, or between two moments. Think of a meetup, a conference talk, a vacation, or a public holiday.</p>60 <p>One word of caution on terms. Everywhere else in this manual, "event" means any signed Nostr event from <a href="01.html">NIP-01</a>. This chapter always says <strong>calendar event</strong> for the scheduling object. It says <strong>event</strong> only for the underlying Nostr object.</p>61 <p>The NIP defines four kinds. Kind <code>31922</code> is a <em>date-based</em> calendar event. Kind <code>31923</code> is a <em>time-based</em> calendar event. Kind <code>31924</code> is a <em>calendar</em>: a list that collects calendar events. Kind <code>31925</code> is an <em>RSVP</em>: a user's answer to a calendar event. All four are <strong>addressable</strong> events per <a href="01.html">NIP-01</a>, and users can delete them per <a href="09.html">NIP-09</a>.</p>62 <p>A calendar event does <em>not</em> have to belong to a calendar. It stands on its own. Calendars only group and curate.</p>6364 <figure class="diagram">65 <div class="frame">66 <svg viewBox="0 0 560 220" role="img" aria-label="Relationship map: calendar events of kind 31922 and 31923, a calendar of kind 31924, and an RSVP of kind 31925, linked by a, e, and p tags">67 <rect class="d-actor" x="20" y="80" width="150" height="60" rx="8"/>68 <text class="d-actor-label" x="95" y="105" text-anchor="middle">Calendar event</text>69 <text class="d-note" x="95" y="124" text-anchor="middle">kind 31922 / 31923</text>70 <rect class="d-actor" x="390" y="20" width="150" height="56" rx="8"/>71 <text class="d-actor-label" x="465" y="43" text-anchor="middle">Calendar</text>72 <text class="d-note" x="465" y="62" text-anchor="middle">kind 31924</text>73 <rect class="d-actor" x="390" y="144" width="150" height="56" rx="8"/>74 <text class="d-actor-label" x="465" y="167" text-anchor="middle">RSVP</text>75 <text class="d-note" x="465" y="186" text-anchor="middle">kind 31925</text>76 <path class="d-msg d-flow" d="M172,88 C260,60 300,52 387,44"/>77 <text class="d-label" x="272" y="46" text-anchor="middle">"a" — request inclusion</text>78 <path class="d-msg blue d-flow" d="M387,60 C300,72 260,80 172,100"/>79 <text class="d-label" x="278" y="92" text-anchor="middle">"a" — includes</text>80 <path class="d-msg blue d-flow" d="M387,172 C300,164 260,140 172,120"/>81 <text class="d-label" x="278" y="152" text-anchor="middle">"a" (+ optional "e", "p")</text>82 <circle r="4" fill="#2e5f9e">83 <animateMotion dur="2.6s" repeatCount="indefinite" path="M387,172 C300,164 260,140 172,120"/>84 </circle>85 </svg>86 </div>87 <figcaption>Fig. 52-1 — <b>The four kinds.</b> Calendars point at calendar events. RSVPs point at calendar events. Calendar events may ask a calendar to include them.</figcaption>88 </figure>8990 <div class="box hint">91 <span class="tag">Hint!</span>92 <p>Addressable means: the relay keeps only the latest event per <code>pubkey</code> + <code>kind</code> + <code>d</code> value. Edit a calendar event by publishing a new event with the same <code>d</code> tag. Other events point at it with an <code>a</code> tag: <code>&lt;kind&gt;:&lt;pubkey&gt;:&lt;d value&gt;</code>.</p>93 </div>9495 <h2 class="bar" id="spec"><span class="num">2</span> Common Tags</h2>96 <p>Both calendar event kinds (<code>31922</code> and <code>31923</code>) share one set of tags. The client that creates the calendar event generates the <code>d</code> identifier.</p>9798 <div class="tscroll"><table class="ref">99 <caption>Tags common to kind 31922 and kind 31923</caption>100 <tr><th>Tag</th><th>Use</th><th>Meaning</th></tr>101 <tr><td class="btn">d</td><td>required</td><td>A short unique string identifier. Generated by the client that creates the calendar event.</td></tr>102 <tr><td class="btn">title</td><td>required</td><td>The title of the calendar event.</td></tr>103 <tr><td class="btn">summary</td><td>optional</td><td>A brief description of the calendar event.</td></tr>104 <tr><td class="btn">image</td><td>optional</td><td>The URL of an image for the calendar event.</td></tr>105 <tr><td class="btn">location</td><td>optional, repeated</td><td>A location: an address, GPS coordinates, a meeting room name, or a video-call link.</td></tr>106 <tr><td class="btn">g</td><td>optional</td><td>A geohash. It ties the calendar event to a searchable physical location.</td></tr>107 <tr><td class="btn">p</td><td>optional, repeated</td><td>A participant: 32-byte hex pubkey, optional recommended relay URL, and the participant's role in the meeting.</td></tr>108 <tr><td class="btn">t</td><td>optional, repeated</td><td>A hashtag that categorizes the calendar event.</td></tr>109 <tr><td class="btn">r</td><td>optional, repeated</td><td>A reference link: web page, document, video call, recorded video, and so on.</td></tr>110 <tr><td class="btn">a</td><td>repeated</td><td>A reference to a kind <code>31924</code> calendar. It requests inclusion in that calendar. See below.</td></tr>111 </table></div>112113 <div class="box warn">114 <span class="tag">Warning!</span>115 <p>The <code>name</code> tag is <strong>deprecated</strong>. It held the name of the calendar event. Read it only when <code>title</code> is absent. Never write it in new calendar events.</p>116 </div>117118 <h3>Collaborative calendar event requests</h3>119 <p>A calendar event can carry an <code>a</code> tag that points at a kind <code>31924</code> calendar. Clients should read this as a request: "add me to that calendar". The calendar owner approves by adding a matching <code>a</code> tag to the calendar. This lets many users contribute calendar events to calendars they do not own, subject to the owner's approval.</p>120121 <h2 class="bar"><span class="num">3</span> Date-Based Calendar Event — Kind 31922</h2>122 <p>A date-based calendar event starts on a date and ends before a later date. Use it when the time of day and the time zone do not matter: an anniversary, a public holiday, vacation days. It is an addressable event of kind <code>31922</code>. The <code>.content</code> SHOULD be a description of the calendar event.</p>123 <p>Besides the common tags, it takes two date tags:</p>124 <div class="tscroll"><table class="ref">125 <caption>Kind 31922 date tags</caption>126 <tr><th>Tag</th><th>Use</th><th>Meaning</th></tr>127 <tr><td class="btn">start</td><td>required</td><td>Inclusive start date in ISO 8601 format (<code>YYYY-MM-DD</code>). Must be less than <code>end</code>, if <code>end</code> exists.</td></tr>128 <tr><td class="btn">end</td><td>optional</td><td>Exclusive end date in ISO 8601 format (<code>YYYY-MM-DD</code>). If omitted, the calendar event ends on the same date as <code>start</code>.</td></tr>129 </table></div>130131 <div class="crt">132 <div class="titlebar">Wire format - kind 31922 date-based calendar event</div>133<pre>{134 <span class="k">"id"</span>: <span class="c">&lt;32-byte lowercase hex sha256 of the serialized event&gt;</span>,135 <span class="k">"pubkey"</span>: <span class="c">&lt;32-byte lowercase hex public key of the creator&gt;</span>,136 <span class="k">"created_at"</span>: <span class="c">&lt;unix timestamp, seconds&gt;</span>,137 <span class="k">"kind"</span>: 31922,138 <span class="k">"content"</span>: <span class="s">"&lt;description of calendar event&gt;"</span>,139 <span class="k">"tags"</span>: [140 [<span class="s">"d"</span>, <span class="s">"&lt;random-identifier&gt;"</span>],141 [<span class="s">"title"</span>, <span class="s">"&lt;title of calendar event&gt;"</span>],142 <span class="c">// dates</span>143 [<span class="s">"start"</span>, <span class="s">"&lt;YYYY-MM-DD&gt;"</span>],144 [<span class="s">"end"</span>, <span class="s">"&lt;YYYY-MM-DD&gt;"</span>],145 <span class="c">// location</span>146 [<span class="s">"location"</span>, <span class="s">"&lt;location&gt;"</span>],147 [<span class="s">"g"</span>, <span class="s">"&lt;geohash&gt;"</span>],148 <span class="c">// participants</span>149 [<span class="s">"p"</span>, <span class="s">"&lt;hex pubkey&gt;"</span>, <span class="s">"&lt;relay URL&gt;"</span>, <span class="s">"&lt;role&gt;"</span>],150 [<span class="s">"p"</span>, <span class="s">"&lt;hex pubkey&gt;"</span>, <span class="s">"&lt;relay URL&gt;"</span>, <span class="s">"&lt;role&gt;"</span>]151 ]152}</pre>153 </div>154155 <h2 class="bar"><span class="num">4</span> Time-Based Calendar Event — Kind 31923</h2>156 <p>A time-based calendar event spans a start time and an end time. It is an addressable event of kind <code>31923</code>. The <code>.content</code> should be a description of the calendar event. It is required, but it can be an empty string.</p>157 <p>Besides the common tags, it takes these time tags:</p>158 <div class="tscroll"><table class="ref">159 <caption>Kind 31923 time tags</caption>160 <tr><th>Tag</th><th>Use</th><th>Meaning</th></tr>161 <tr><td class="btn">start</td><td>required</td><td>Inclusive start as a Unix timestamp in seconds. Must be less than <code>end</code>, if <code>end</code> exists.</td></tr>162 <tr><td class="btn">end</td><td>optional</td><td>Exclusive end as a Unix timestamp in seconds. If omitted, the calendar event ends instantaneously.</td></tr>163 <tr><td class="btn">start_tzid</td><td>optional</td><td>Time zone of the start timestamp, from the IANA Time Zone Database. Example: <code>America/Costa_Rica</code>.</td></tr>164 <tr><td class="btn">end_tzid</td><td>optional</td><td>Time zone of the end timestamp, from the IANA Time Zone Database. If omitted and <code>start_tzid</code> is present, the end uses the start's time zone.</td></tr>165 <tr><td class="btn">D</td><td>required</td><td>The day-granularity Unix timestamp of a day the calendar event takes place on: <code>floor(unix_seconds() / seconds_in_one_day)</code>. Include multiple <code>D</code> tags — one SHOULD exist for every day the calendar event covers.</td></tr>166 </table></div>167168 <figure class="diagram">169 <div class="frame">170 <svg viewBox="0 0 560 150" role="img" aria-label="A time-based calendar event spanning two day buckets carries one D tag per covered day">171 <text class="d-actor-label" x="10" y="20">Day buckets: floor(unix seconds / 86400)</text>172 <rect class="d-actor" x="30" y="36" width="160" height="40" rx="6"/>173 <text class="d-label" x="110" y="61" text-anchor="middle">day 20619</text>174 <rect class="d-actor" x="200" y="36" width="160" height="40" rx="6"/>175 <text class="d-label" x="280" y="61" text-anchor="middle">day 20620</text>176 <rect class="d-actor" x="370" y="36" width="160" height="40" rx="6"/>177 <text class="d-label" x="450" y="61" text-anchor="middle">day 20621</text>178 <rect x="120" y="92" width="220" height="22" rx="4" fill="#f26a00"/>179 <text class="d-label" x="230" y="107" text-anchor="middle" fill="#fff">calendar event: start → end</text>180 <text class="d-note" x="230" y="138" text-anchor="middle">tags: ["D","20619"] and ["D","20620"] — one per covered day</text>181 </svg>182 </div>183 <figcaption>Fig. 52-2 — <b>The D tag.</b> A calendar event that crosses midnight covers two day buckets, so it carries two <code>D</code> tags. Relays index <code>D</code>, so clients can query one day cheaply.</figcaption>184 </figure>185186 <div class="box tech">187 <span class="tag">Tech Note</span>188 <p>Two source quirks. First: the source's example tag <code>["D", "82549"]</code> maps to a day in the year 2196; a present-day value is near 20600. Second: <code>D</code> is marked required, but it was added in 2026 — kind <code>31923</code> events published before then do not carry it. Query by <code>#D</code> with a fallback.</p>189 </div>190191 <div class="crt">192 <div class="titlebar">Wire format - kind 31923 time-based calendar event</div>193<pre>{194 <span class="k">"id"</span>: <span class="c">&lt;32-byte lowercase hex sha256 of the serialized event&gt;</span>,195 <span class="k">"pubkey"</span>: <span class="c">&lt;32-byte lowercase hex public key of the creator&gt;</span>,196 <span class="k">"created_at"</span>: <span class="c">&lt;unix timestamp, seconds&gt;</span>,197 <span class="k">"kind"</span>: 31923,198 <span class="k">"content"</span>: <span class="s">"&lt;description of calendar event&gt;"</span>,199 <span class="k">"tags"</span>: [200 [<span class="s">"d"</span>, <span class="s">"&lt;random-identifier&gt;"</span>],201 [<span class="s">"title"</span>, <span class="s">"&lt;title of calendar event&gt;"</span>],202 [<span class="s">"summary"</span>, <span class="s">"&lt;brief description&gt;"</span>],203 [<span class="s">"image"</span>, <span class="s">"&lt;image URL&gt;"</span>],204 <span class="c">// timestamps</span>205 [<span class="s">"start"</span>, <span class="s">"&lt;unix timestamp in seconds&gt;"</span>],206 [<span class="s">"end"</span>, <span class="s">"&lt;unix timestamp in seconds&gt;"</span>],207 [<span class="s">"D"</span>, <span class="s">"&lt;floor(unix seconds / 86400)&gt;"</span>],208 [<span class="s">"start_tzid"</span>, <span class="s">"&lt;IANA time zone id&gt;"</span>],209 [<span class="s">"end_tzid"</span>, <span class="s">"&lt;IANA time zone id&gt;"</span>],210 <span class="c">// location</span>211 [<span class="s">"location"</span>, <span class="s">"&lt;location&gt;"</span>],212 [<span class="s">"g"</span>, <span class="s">"&lt;geohash&gt;"</span>],213 <span class="c">// participants</span>214 [<span class="s">"p"</span>, <span class="s">"&lt;hex pubkey&gt;"</span>, <span class="s">"&lt;relay URL&gt;"</span>, <span class="s">"&lt;role&gt;"</span>],215 [<span class="s">"p"</span>, <span class="s">"&lt;hex pubkey&gt;"</span>, <span class="s">"&lt;relay URL&gt;"</span>, <span class="s">"&lt;role&gt;"</span>]216 ]217}</pre>218 </div>219220 <h2 class="bar"><span class="num">5</span> Calendar — Kind 31924</h2>221 <p>A calendar is a collection of calendar events. It is an addressable list event of kind <code>31924</code>. One user can keep many calendars: personal, work, travel, meetups, conferences. The <code>.content</code> should be a detailed description of the calendar. It is required, but it can be an empty string.</p>222 <div class="tscroll"><table class="ref">223 <caption>Kind 31924 tags</caption>224 <tr><th>Tag</th><th>Use</th><th>Meaning</th></tr>225 <tr><td class="btn">d</td><td>required</td><td>A universally unique identifier. Generated by the client that creates the calendar.</td></tr>226 <tr><td class="btn">title</td><td>required</td><td>The calendar title.</td></tr>227 <tr><td class="btn">a</td><td>repeated</td><td>A reference to a kind <code>31922</code> or <code>31923</code> calendar event that this calendar includes or responds to.</td></tr>228 </table></div>229 <p>A calendar can accept requests from other users. When a calendar event points at the calendar with an <code>a</code> tag, that is a request for inclusion. The owner answers by adding the calendar event's coordinates to the calendar.</p>230 <div class="crt">231 <div class="titlebar">Wire format - kind 31924 calendar</div>232<pre>{233 <span class="k">"id"</span>: <span class="c">&lt;32-byte lowercase hex sha256 of the serialized event&gt;</span>,234 <span class="k">"pubkey"</span>: <span class="c">&lt;32-byte lowercase hex public key of the creator&gt;</span>,235 <span class="k">"created_at"</span>: <span class="c">&lt;unix timestamp, seconds&gt;</span>,236 <span class="k">"kind"</span>: 31924,237 <span class="k">"content"</span>: <span class="s">"&lt;description of calendar&gt;"</span>,238 <span class="k">"tags"</span>: [239 [<span class="s">"d"</span>, <span class="s">"&lt;random-identifier&gt;"</span>],240 [<span class="s">"title"</span>, <span class="s">"&lt;calendar title&gt;"</span>],241 [<span class="s">"a"</span>, <span class="s">"&lt;31922 or 31923&gt;:&lt;author pubkey&gt;:&lt;d value&gt;"</span>, <span class="s">"&lt;relay URL&gt;"</span>],242 [<span class="s">"a"</span>, <span class="s">"&lt;31922 or 31923&gt;:&lt;author pubkey&gt;:&lt;d value&gt;"</span>, <span class="s">"&lt;relay URL&gt;"</span>]243 ]244}</pre>245 </div>246247 <h2 class="bar"><span class="num">6</span> Calendar Event RSVP — Kind 31925</h2>248 <p>An RSVP answers a calendar event. It states the user's attendance intention. It is an addressable event of kind <code>31925</code>. The <code>.content</code> is optional: a free-form note that adds context to the response.</p>249 <p>Invitations work through <code>p</code> tags. If a calendar event tags a pubkey, read that as an invitation from the creator to that user. Clients MAY prompt the tagged user to RSVP. But any user may RSVP, tagged or not. Clients MAY prompt the calendar event creator to invite an untagged user who RSVP'd. Clients also MAY ignore such RSVPs.</p>250 <p>Two things stay intentionally undefined. The NIP does not define who is authorized to attend when an untagged user RSVPs; the calendar event creator decides the semantics. The NIP also does not define what happens when a calendar event changes after an RSVP is submitted.</p>251 <div class="tscroll"><table class="ref">252 <caption>Kind 31925 tags</caption>253 <tr><th>Tag</th><th>Use</th><th>Meaning</th></tr>254 <tr><td class="btn">a</td><td>required</td><td>Coordinates of the kind <code>31922</code> or <code>31923</code> calendar event being answered.</td></tr>255 <tr><td class="btn">e</td><td>optional</td><td>The event id of the specific calendar event revision being answered. If present, clients SHOULD read the RSVP as an answer to that revision. Clients MAY treat it as not applying to other revisions.</td></tr>256 <tr><td class="btn">d</td><td>required</td><td>A universally unique identifier. Generated by the client that creates the RSVP.</td></tr>257 <tr><td class="btn">status</td><td>required</td><td><code>accepted</code>, <code>declined</code>, or <code>tentative</code>. The attendance status for the referenced calendar event.</td></tr>258 <tr><td class="btn">fb</td><td>optional</td><td><code>free</code> or <code>busy</code>. States whether the user is free or busy for the duration of the calendar event. Omit or ignore this tag when <code>status</code> is <code>declined</code>.</td></tr>259 <tr><td class="btn">p</td><td>optional</td><td>The pubkey of the calendar event's author. It lets clients query all RSVPs that pertain to that author.</td></tr>260 </table></div>261 <div class="crt">262 <div class="titlebar">Wire format - kind 31925 RSVP</div>263<pre>{264 <span class="k">"id"</span>: <span class="c">&lt;32-byte lowercase hex sha256 of the serialized event&gt;</span>,265 <span class="k">"pubkey"</span>: <span class="c">&lt;32-byte lowercase hex public key of the creator&gt;</span>,266 <span class="k">"created_at"</span>: <span class="c">&lt;unix timestamp, seconds&gt;</span>,267 <span class="k">"kind"</span>: 31925,268 <span class="k">"content"</span>: <span class="s">"&lt;note&gt;"</span>,269 <span class="k">"tags"</span>: [270 [<span class="s">"e"</span>, <span class="s">"&lt;kind 31922 or 31923 event id&gt;"</span>, <span class="s">"&lt;relay URL&gt;"</span>],271 [<span class="s">"a"</span>, <span class="s">"&lt;31922 or 31923&gt;:&lt;author pubkey&gt;:&lt;d value&gt;"</span>, <span class="s">"&lt;relay URL&gt;"</span>],272 [<span class="s">"d"</span>, <span class="s">"&lt;random-identifier&gt;"</span>],273 [<span class="s">"status"</span>, <span class="s">"&lt;accepted / declined / tentative&gt;"</span>],274 [<span class="s">"fb"</span>, <span class="s">"&lt;free / busy&gt;"</span>],275 [<span class="s">"p"</span>, <span class="s">"&lt;hex pubkey of the calendar event author&gt;"</span>, <span class="s">"&lt;relay URL&gt;"</span>]276 ]277}</pre>278 </div>279 <div class="box tech">280 <span class="tag">Tech Note</span>281 <p>Source quirks in this section. The RSVP example JSON in the source is malformed: the <code>e</code> tag line lacks a closing quote and a trailing comma. Also, the <code>d</code> tag is a "short unique string" in the common-tags list, but a "universally unique identifier" here and for calendars. Treat both as: any client-generated unique string.</p>282 </div>283284 <figure class="diagram">285 <div class="frame">286 <svg viewBox="0 0 560 250" role="img" aria-label="Sequence diagram: organizer publishes a time-based calendar event tagging a guest, the guest's client prompts, and the guest publishes an RSVP">287 <line class="d-wire" x1="110" y1="40" x2="110" y2="235" stroke-dasharray="3 4"/>288 <line class="d-wire" x1="450" y1="40" x2="450" y2="235" stroke-dasharray="3 4"/>289 <rect class="d-actor" x="55" y="8" width="110" height="30" rx="6"/>290 <text class="d-actor-label" x="110" y="28" text-anchor="middle">Organizer</text>291 <rect class="d-actor" x="395" y="8" width="110" height="30" rx="6"/>292 <text class="d-actor-label" x="450" y="28" text-anchor="middle">Guest</text>293 <path class="d-msg d-flow" d="M110,70 L445,70"/>294 <text class="d-label" x="280" y="63" text-anchor="middle">kind 31923 with ["p", guest_pubkey] — invitation</text>295 <text class="d-note" x="280" y="105" text-anchor="middle">Guest's client MAY prompt: attend?</text>296 <path class="d-msg blue d-flow" d="M450,140 L115,140"/>297 <text class="d-label" x="280" y="133" text-anchor="middle">kind 31925 with ["a", coords], ["status","accepted"]</text>298 <text class="d-note" x="280" y="175" text-anchor="middle">Untagged users may RSVP too. The organizer's client MAY</text>299 <text class="d-note" x="280" y="192" text-anchor="middle">prompt to invite them — or ignore the RSVP.</text>300 <circle r="4" fill="#2e5f9e">301 <animateMotion dur="2.6s" begin="1.3s" repeatCount="indefinite" path="M450,140 L115,140"/>302 </circle>303 </svg>304 </div>305 <figcaption>Fig. 52-3 — <b>Invitation and RSVP.</b> A <code>p</code> tag invites. A kind <code>31925</code> event answers with a status.</figcaption>306 </figure>307308 <h2 class="bar"><span class="num">7</span> Intentionally Unsupported: Recurrence</h2>309 <p>This NIP does not support recurring calendar events. Recurrence brings heavy complexity: time zone differences between invitees, daylight saving time, leap years, multiple calendar systems, one-off changes in schedule or metadata.</p>310 <p>The NIP pushes that complexity up to clients. A client that wants recurrence publishes individual calendar events with duplicated metadata, one per occurrence.</p>311312 <h2 class="bar" id="examples"><span class="num">8</span> Worked Example</h2>313 <p>Alice organizes a meetup that runs from 17:00 UTC on 2026-06-15 to 01:00 UTC on 2026-06-16. It crosses midnight, so it carries two <code>D</code> tags. She invites Bob with a <code>p</code> tag and asks a community calendar to include the event.</p>314 <div class="crt">315 <div class="titlebar">Alice's calendar event - kind 31923</div>316<pre>{317 <span class="k">"kind"</span>: 31923,318 <span class="k">"pubkey"</span>: <span class="s">"a1ce4f2b…"</span>,319 <span class="k">"created_at"</span>: 1780000000,320 <span class="k">"content"</span>: <span class="s">"Monthly Nostr meetup. Talks, pizza, key signing."</span>,321 <span class="k">"tags"</span>: [322 [<span class="s">"d"</span>, <span class="s">"meetup-2026-06"</span>],323 [<span class="s">"title"</span>, <span class="s">"Nostr Meetup #14"</span>],324 [<span class="s">"summary"</span>, <span class="s">"Talks and pizza"</span>],325 [<span class="s">"start"</span>, <span class="s">"1781542800"</span>],326 [<span class="s">"end"</span>, <span class="s">"1781571600"</span>],327 [<span class="s">"D"</span>, <span class="s">"20619"</span>], [<span class="s">"D"</span>, <span class="s">"20620"</span>],328 [<span class="s">"start_tzid"</span>, <span class="s">"Europe/Berlin"</span>],329 [<span class="s">"location"</span>, <span class="s">"c-base, Rungestr. 20, Berlin"</span>],330 [<span class="s">"g"</span>, <span class="s">"u33db2m"</span>],331 [<span class="s">"p"</span>, <span class="s">"b0b1d2e3…"</span>, <span class="s">"wss://relay.example.com"</span>, <span class="s">"speaker"</span>],332 [<span class="s">"t"</span>, <span class="s">"meetup"</span>],333 [<span class="s">"r"</span>, <span class="s">"https://meetup.example.com/14"</span>],334 [<span class="s">"a"</span>, <span class="s">"31924:ca1e4da5…:berlin-community"</span>]335 ],336 <span class="c">"id": …, "sig": …</span>337}</pre>338 </div>339 <p>Bob's client sees the <code>p</code> tag and prompts him. He accepts:</p>340 <div class="crt">341 <div class="titlebar">Bob's RSVP - kind 31925</div>342<pre>{343 <span class="k">"kind"</span>: 31925,344 <span class="k">"pubkey"</span>: <span class="s">"b0b1d2e3…"</span>,345 <span class="k">"content"</span>: <span class="s">"See you there!"</span>,346 <span class="k">"tags"</span>: [347 [<span class="s">"a"</span>, <span class="s">"31923:a1ce4f2b…:meetup-2026-06"</span>, <span class="s">"wss://relay.example.com"</span>],348 [<span class="s">"e"</span>, <span class="s">"9e0c55aa…"</span>, <span class="s">"wss://relay.example.com"</span>],349 [<span class="s">"d"</span>, <span class="s">"rsvp-77f3"</span>],350 [<span class="s">"status"</span>, <span class="s">"accepted"</span>],351 [<span class="s">"fb"</span>, <span class="s">"busy"</span>],352 [<span class="s">"p"</span>, <span class="s">"a1ce4f2b…"</span>]353 ],354 <span class="c">"created_at": …, "id": …, "sig": …</span>355}</pre>356 </div>357 <p>Carol owns the community calendar. She approves Alice's request by adding the coordinates. A client then queries the day and the RSVPs:</p>358 <div class="crt">359 <div class="titlebar">Session transcript - wss://relay.example.com</div>360<pre><span class="c">-- Carol approves: her calendar now lists Alice's event --</span>361<span class="send">→ ["EVENT", {"kind":31924, "tags":[["d","berlin-community"],362 ["title","Berlin Community Calendar"],363 ["a","31923:a1ce4f2b…:meetup-2026-06","wss://relay.example.com"]], …}]</span>364<span class="recv">← ["OK", "c4a7e1…", true, ""]</span>365366<span class="c">-- what happens on June 15? query the day bucket --</span>367<span class="send">→ ["REQ", "day", {"kinds":[31923], "#D":["20619"]}]</span>368<span class="recv">← ["EVENT", "day", {"kind":31923, "tags":[["title","Nostr Meetup #14"], …]}]</span>369<span class="recv">← ["EOSE", "day"]</span>370371<span class="c">-- who is coming? query RSVPs by coordinates --</span>372<span class="send">→ ["REQ", "rsvps", {"kinds":[31925], "#a":["31923:a1ce4f2b…:meetup-2026-06"]}]</span>373<span class="recv">← ["EVENT", "rsvps", {"kind":31925, "tags":[["status","accepted"],["fb","busy"], …]}]</span>374<span class="recv">← ["EOSE", "rsvps"]</span></pre>375 </div>376377 <h2 class="bar" id="history"><span class="num">9</span> Version History</h2>378 <p>Terry Yiu proposed NIP-52 in mid-2023. The spec has since traded UUIDs for plain identifiers, gained RSVP pointers, and grown day-bucket indexing. Notable changes, newest first:</p>379 <ul class="patchnotes">380 <li><span class="ver">2026</span><span class="when">2026-02</span>Added the <code>D</code> day-granularity timestamp tag ("timehashes") to kind <code>31923</code>, so clients can query calendar events by day.</li>381 <li><span class="ver">2025</span><span class="when">2025-08</span>Added collaborative calendar event requests: an <code>a</code> tag on a calendar event now asks a kind <code>31924</code> calendar for inclusion.</li>382 <li><span class="ver">2025</span><span class="when">2025-05</span>Simplified the spec; dropped the UUID requirement — <code>d</code> is now any client-generated unique string.</li>383 <li><span class="ver">2024</span><span class="when">2024-08</span>RSVPs gained the optional <code>e</code> (revision) and <code>p</code> (author) tags, revised to stay backwards compatible with the required <code>a</code> tag. Renamed "parameterized replaceable" events to "addressable".</li>384 <li><span class="ver">2023</span><span class="when">2023-12</span>Deprecated <code>name</code> in favor of <code>title</code>; made <code>.content</code> required; decoupled the calendar identifier from the calendar name.</li>385 <li class="minor"><span class="ver">2023-25</span><span class="when">2023-2025</span>Housekeeping: kinds written as integers, NIP-12 mention removed, label cruft and typos fixed.</li>386 <li><span class="ver">Origin</span><span class="when">2023-06</span>Terry Yiu published "NIP-52: Calendar Events" with the four kinds 31922-31925.</li>387 </ul>388389 <div class="credits">390 <h3 class="cardhead">Original Proposal - Credits</h3>391 <table>392 <tr><td>Author</td><td>Terry Yiu</td></tr>393 <tr><td>First commit</td><td>2023-06-10 — “NIP-52: Calendar Events”</td></tr>394 <tr><td>Status</td><td>draft - optional — clients implement it to offer scheduling</td></tr>395 <tr><td>Source</td><td><a href="https://github.com/nostr-protocol/nips/blob/master/52.md">52.md on GitHub</a> - <a href="https://github.com/nostr-protocol/nips/commits/master/52.md">full change history</a></td></tr>396 </table>397 </div>398399 <h2 class="bar"><span class="num">10</span> See Also</h2>400 <ul>401 <li><a href="01.html">NIP-01</a> — the base protocol: addressable events, <code>a</code>/<code>e</code>/<code>p</code> tags, and tag-filter queries used here.</li>402 <li><a href="09.html">NIP-09</a> — event deletion; calendar events are deletable through it.</li>403 <li><a href="51.html">NIP-51</a> — lists; a kind <code>31924</code> calendar is a purpose-built addressable list.</li>404 <li><a href="53.html">NIP-53</a> — live streaming and spaces; live activities that pair well with scheduled calendar events.</li>405 <li><a href="19.html">NIP-19</a> — <code>naddr</code> encoding for sharing the coordinates of a calendar event.</li>406 </ul>407 </div>408409 <aside>410 <div class="cartridge">411 <div class="inner">412 <h3 class="cardhead">Spec Card</h3>413 <div class="lights"><span class="led on"></span><span class="led on"></span><span class="led on"></span></div>414 <dl>415 <dt>Status</dt><dd><span class="chip draft">draft</span><span class="chip">optional</span></dd>416 <dt>Defines</dt><dd>date/time calendar events - calendars - RSVPs</dd>417 <dt>Kinds</dt><dd>31922 - 31923 - 31924 - 31925</dd>418 <dt>Requires</dt><dd><a href="01.html">NIP-01</a> - <a href="09.html">NIP-09</a></dd>419 <dt>Key tags</dt><dd>d, title, start, end, D, status, fb</dd>420 <dt>First commit</dt><dd>2023-06-10</dd>421 <dt>Last updated</dt><dd>2026-02-13</dd>422 </dl>423 </div>424 </div>425 </aside>426 </main>427428 <nav class="navbtns">429 <a href="51.html">◀ NIP-51: Lists</a>430 <a href="53.html">NIP-53: Live Streaming and Spaces ▶</a>431 </nav>432433 <footer class="pagefoot">434 <a href="../index.html">Nostr Protocol Manual</a>435 <span class="pageno">NIP 52 / F4</span>436 </footer>437</div>438439<script src="../assets/webmcp.js" defer></script>440</body>441</html>