1 Overview
A user often starts a post and finishes it later, on another device. Nostr has no server-side account to hold that unfinished text. This NIP fills the gap with a draft wrap: an encrypted container event for an unsigned draft of any other kind.
The NIP defines three kinds. Kind 31234 is the draft wrap itself. Kind 1234 is a checkpoint that records a revision of a draft. Kind 10013 is a relay list for private content, which tells clients where to store draft wraps.
The draft stays private because the client encrypts it with NIP-44 to the signer's own public key. Only the author can decrypt it. Relays see an opaque string, never the draft text.
A draft wrap is a container, not a post. The inner draft event is unsigned. When the user hits publish, the client signs the inner event, sends it as its real kind, and deletes the wrap.
2 The Draft Wrap - Kind 31234
Kind 31234 is an addressable event (see NIP-01 storage classes). It stores one unsigned draft event of any other kind. Build it in three steps. Serialize the draft event to a JSON string. Encrypt that string with NIP-44 to the signer's own public key. Place the ciphertext in content.
{
"kind": 31234,
"tags": [
["d", <identifier>],
["k", <kind of the draft event>], // required
["expiration", <unix ts, ~now + 90 days>] // recommended
],
"content": nip44Encrypt(JSON.stringify(draft_event)),
// other fields per NIP-01
}
| Tag | Required | Rule |
|---|---|---|
| d | yes | The identifier of this draft. Makes the event addressable; a new version replaces the old one. |
| k | yes | The kind number of the inner draft event. Lets clients filter drafts by target kind without decrypting. |
| expiration | recommended | A NIP-40 expiration tag. The source suggests about 90 days from creation. |
Two more rules apply to the wrap:
- Deletion. A blank
contentfield signals that the author deleted the draft. Publish a new version of the same addressable event with emptycontent. - Where to publish. Clients SHOULD publish kind
31234events to the relays listed in the user's kind10013event (see §4).
The source example writes the expiration value as the literal string "now + 90 days". That is pseudocode. NIP-40 requires a unix timestamp string. Compute the timestamp; do not copy the literal.
3 Checkpoints - Kind 1234
Kind 1234 defines a checkpoint. A checkpoint belongs to one parent kind 31234 draft wrap. Checkpoints can provide a revision history of the parent draft.
A checkpoint points to its parent with an a tag. Its content holds the draft revision, encrypted the same way as the parent: JSON-stringify the draft event, then encrypt with NIP-44.
{
"kind": 1234,
"tags": [
["a", "31234:<pubkey>:<identifier>"]
],
"content": nip44Encrypt(JSON.stringify(draft_event))
}
Kind 1234 sits in the regular storage range, so relays keep every checkpoint. The spec does not say what happens to checkpoints when the parent draft is blanked or expires. Clients should add their own NIP-40 expiration tags to checkpoints, or delete them with NIP-09.
a tags.4 Relay List for Private Content - Kind 10013
Kind 10013 is a replaceable event. It indicates the user's preferred relays for private events such as draft wraps. The public tags array stays empty. The relay list itself is private.
The event MUST include a list of relay URLs in private tags. Private tags are a JSON-stringified tag array, encrypted with NIP-44 to the signer's own keys, and placed in content.
{
"kind": 10013,
"tags": [],
"content": nip44Encrypt(
JSON.stringify([
["relay", "wss://myrelay.mydomain.com"]
])
)
// ...other fields per NIP-01
}
- Clients MUST publish kind
10013events to the author's NIP-65writerelays. Any client of the user can then find the list. - Private storage relays SHOULD require NIP-42 authentication. They SHOULD only allow downloads of events signed by the authenticated user. This recommendation keeps ciphertext and metadata away from strangers.
Encryption hides the draft text, not the metadata. The k tag, the d tag, and the timestamps are public on any relay that serves the event. Use an authenticated private relay if that metadata matters to you.
5 Worked Example
Alice starts a long-form article (kind 30023) on her laptop. Her client wraps the unsigned draft, stores it, and later blanks it after she publishes. The inner draft event looks like this before encryption:
{
"pubkey": "a1fc5dfd…9b03",
"created_at": 1767225600,
"kind": 30023,
"tags": [["d", "my-article"], ["title", "Why relays matter"]],
"content": "Relays are simple servers that…"
// no id, no sig — the draft is unsigned
}
-- laptop stores the draft wrap on the private relay -- → ["EVENT", {"kind":31234,"pubkey":"a1fc5dfd…9b03","created_at":1767225601, "tags":[["d","draft-my-article"],["k","30023"],["expiration","1775001601"]], "content":"AsWxoZ0e…Jw2Q==","id":"7d21c04b…","sig":"90ffab12…"}] ← ["OK", "7d21c04b…", true, ""] -- phone finds the draft later -- → ["REQ", "drafts", {"kinds":[31234], "authors":["a1fc5dfd…9b03"]}] ← ["EVENT", "drafts", {"kind":31234, "tags":[["d","draft-my-article"],["k","30023"], …], …}] ← ["EOSE", "drafts"] -- the phone decrypts content with NIP-44 and restores the editor -- -- after publishing, the laptop blanks the wrap to delete the draft -- → ["EVENT", {"kind":31234, "tags":[["d","draft-my-article"],["k","30023"]], "content":"", "created_at":1767312000, …}] ← ["OK", "e93aa1c7…", true, ""]
Between edits, Alice's client may also store kind 1234 checkpoints with the tag ["a", "31234:a1fc5dfd…9b03:draft-my-article"]. Each checkpoint keeps one encrypted revision, so she can roll back.
6 Version History
The draft-event idea started inside the old NIP-35 draft in March 2024 and moved to its own number soon after. Notable changes, newest first:
- 20262026-05Reworked as "Draft Wraps" (PR #1653): kind
31234wraps, kind1234checkpoints, and the kind10013private-content relay list in its current form. - 20252025-10Improved the draft-event spec (PR #2016).
- 20242024-05Moved from the NIP-35 draft into NIP-37; added private outbox relays for draft storage.
- 20242024-03Added draft deletion by blanking
content, so drafts die even on relays without deletion support. - Origin2024-03Vitor Pamplona wrote the first encrypted draft-event spec.
Git rename detection chains this file into the unrelated history of the old NIP-35 pages (torrents, user discovery). The entries above keep only the commits about drafts.
Original Proposal - Credits
| Author | Vitor Pamplona |
| First commit | 2024-05-30 — “moves from NIP-35 to NIP-37” (draft spec first written 2024-03) |
| Status | draft - optional — clients may skip drafts entirely |
| Source | 37.md on GitHub - full change history |
7 See Also
- NIP-01 — the base protocol; addressable and replaceable storage classes used by kinds
31234and10013. - NIP-44 — the encryption scheme that protects the draft content and the private relay list.
- NIP-40 — expiration tags, recommended on every draft wrap.
- NIP-42 — relay authentication, recommended for private storage relays.
- NIP-65 — the relay list metadata; kind
10013goes to itswriterelays. - NIP-09 — event deletion requests, useful for cleaning up checkpoints.