Appearance
Nostr Events
Overview
Events are the fundamental data structure in the Nostr protocol. All information exchanged on Nostr is formatted as events. Each event is created by a user (identified by their public key), serialized, signed, and then distributed to relays.
Event Structure
A Nostr event is a JSON object with the following fields:
Field | Type | Description |
---|---|---|
id | string | 32-bytes lowercase hex-encoded sha256 hash of the serialized event data |
pubkey | string | 32-bytes lowercase hex-encoded public key of the event creator |
created_at | integer | Unix timestamp (seconds) when the event was created |
kind | integer | Integer between 0 and 65535 identifying the event type |
tags | array | Array of arrays of strings, representing the event's tags |
content | string | Arbitrary string content, format depends on event kind |
sig | string | 64-bytes lowercase hex of the signature |
Event Serialization and ID Generation
To obtain the id
field value, the event data must be serialized and hashed:
Create an array with the following elements in order:
[ 0, <pubkey, as a lowercase hex string>, <created_at, as a number>, <kind, as a number>, <tags, as an array of arrays of non-null strings>, <content, as a string> ]
Serialize this array to a JSON string with the following rules:
- Use UTF-8 encoding
- No whitespace, line breaks, or unnecessary formatting
- Proper character escaping in the content field:
- Line break (
0x0A
):\n
- Double quote (
0x22
):\"
- Backslash (
0x5C
):\\
- Carriage return (
0x0D
):\r
- Tab character (
0x09
):\t
- Backspace (
0x08
):\b
- Form feed (
0x0C
):\f
- Line break (
Calculate the SHA-256 hash of this serialized string
Encode the resulting hash as a lowercase hex string
Event Signature
After calculating the event ID, the creator signs the ID using their private key according to the Schnorr signatures standard for the curve secp256k1
. The resulting signature is hex-encoded and stored in the sig
field.
Event Kinds
Events are categorized by their kind
value:
Regular (1 ≤ kind < 10000 || 4 ≤ kind < 45 || kind == 1 || kind == 2)
- Expected to be stored by relays
- Used for persistent content like notes, articles, etc.
Replaceable (10000 ≤ kind < 20000 || kind == 0 || kind == 3)
- For each combination of
pubkey
andkind
, only the latest event is stored - Used for profile metadata, contact lists, etc.
- For each combination of
Ephemeral (20000 ≤ kind < 30000)
- Not expected to be stored by relays
- Used for temporary messages like chat
Addressable (30000 ≤ kind < 40000)
- Identified by a combination of
kind
,pubkey
, andd
tag value - For each unique combination, only the latest event is stored
- Identified by a combination of
Tags
Tags provide additional metadata and relationships for events. They are represented as arrays of strings:
[
["<tag-name>", "<tag-value>", "...additional optional fields"],
// more tags
]
Standard Tags
e-tag: References another event
- Format:
["e", "<event-id>", "<optional-relay-url>", "<optional-marker>"]
- Format:
p-tag: References a pubkey (user)
- Format:
["p", "<pubkey>", "<optional-relay-url>", "<optional-petname>"]
- Format:
a-tag: References an addressable/replaceable event
- Addressable:
["a", "<kind>:<pubkey>:<d-tag-value>", "<optional-relay-url>"]
- Replaceable:
["a", "<kind>:<pubkey>:", "<optional-relay-url>"]
- Addressable:
Example Event
json
{
"id": "4376c65d2f232afbe9b882a35baa4f6fe8667c4e684749af565f981833ed6a65",
"pubkey": "79dff8f82963424e0bb02708a22e44b4980893e3a4be0fa3cb60a43b946764e3",
"created_at": 1671217411,
"kind": 1,
"tags": [
["e", "5c83da77af1dec6d7289834998ad7aafbd9e2191396d75ec3cc27f5a77226f36", "wss://nostr.example.com"],
["p", "f7234bd4c1394dda46d09f35bd384dd30cc552ad5541990f98844fb06676e9ca"]
],
"content": "This is a reply to another note!",
"sig": "908a15e46fb4d8675bab026fc230a0e3542bfade63da02d542fb78b2a8513fcd0092619a2c8c1221e581946e0191f2af505dfdf8657a414dbca329186f009262"
}