- Introduced a comprehensive skill for the Nostr protocol, covering client and relay implementation, event structure, cryptographic operations, and best practices. - Added detailed reference files including an overview of NIPs, event kinds, common mistakes, and a complete guide to the Nostr protocol. - Included quick start examples and a checklist for implementing Nostr features effectively. - Ensured documentation is aligned with the latest standards and practices for Nostr development.
1171 lines
23 KiB
Markdown
1171 lines
23 KiB
Markdown
# Nostr Implementation Possibilities (NIPs) - Complete Overview
|
|
|
|
This document provides detailed descriptions of all standard NIPs from the nostr-protocol/nips repository.
|
|
|
|
## Core Protocol NIPs
|
|
|
|
### NIP-01: Basic Protocol Flow Description
|
|
|
|
**Status**: Mandatory for all implementations
|
|
|
|
The foundational NIP that defines the entire Nostr protocol.
|
|
|
|
#### Events
|
|
|
|
Events are the only object type in Nostr. Structure:
|
|
|
|
```json
|
|
{
|
|
"id": "<32-bytes lowercase hex>",
|
|
"pubkey": "<32-bytes lowercase hex>",
|
|
"created_at": "<unix timestamp>",
|
|
"kind": "<integer>",
|
|
"tags": [["<key>", "<value>", ...]],
|
|
"content": "<string>",
|
|
"sig": "<64-bytes hex>"
|
|
}
|
|
```
|
|
|
|
**Event ID Calculation**:
|
|
1. Serialize to JSON array: `[0, pubkey, created_at, kind, tags, content]`
|
|
2. UTF-8 encode
|
|
3. Calculate SHA256 hash
|
|
4. Result is the event ID
|
|
|
|
**Signature**:
|
|
- Schnorr signature of the event ID
|
|
- Uses secp256k1 curve
|
|
- 64-byte hex-encoded
|
|
|
|
#### Communication Protocol
|
|
|
|
All communication happens over WebSocket.
|
|
|
|
**Client Messages**:
|
|
|
|
1. `["EVENT", <event>]` - Publish event
|
|
2. `["REQ", <subscription_id>, <filter>, ...]` - Subscribe
|
|
3. `["CLOSE", <subscription_id>]` - Unsubscribe
|
|
|
|
**Relay Messages**:
|
|
|
|
1. `["EVENT", <subscription_id>, <event>]` - Send event
|
|
2. `["OK", <event_id>, <accepted>, <message>]` - Command result
|
|
3. `["EOSE", <subscription_id>]` - End of stored events
|
|
4. `["CLOSED", <subscription_id>, <message>]` - Forced close
|
|
5. `["NOTICE", <message>]` - Human-readable notice
|
|
|
|
#### Filters
|
|
|
|
Filter object fields (all optional):
|
|
- `ids`: List of event IDs (prefix match)
|
|
- `authors`: List of pubkeys (prefix match)
|
|
- `kinds`: List of event kinds
|
|
- `#<single-letter>`: Tag queries
|
|
- `since`: Unix timestamp (events after)
|
|
- `until`: Unix timestamp (events before)
|
|
- `limit`: Maximum events to return
|
|
|
|
A filter matches if ALL conditions are met. Within arrays, conditions are ORed.
|
|
|
|
#### Basic Event Kinds
|
|
|
|
- `0`: Metadata (user profile)
|
|
- `1`: Text note
|
|
- `2`: Recommend relay (deprecated)
|
|
|
|
### NIP-02: Contact List and Petnames
|
|
|
|
**Status**: Widely implemented
|
|
|
|
Defines event kind `3` for user contact lists (following lists).
|
|
|
|
**Format**:
|
|
```json
|
|
{
|
|
"kind": 3,
|
|
"tags": [
|
|
["p", "<pubkey>", "<relay-url>", "<petname>"]
|
|
],
|
|
"content": "<relay-list-json>"
|
|
}
|
|
```
|
|
|
|
**Characteristics**:
|
|
- Replaceable event (latest version is authoritative)
|
|
- Each `p` tag is a followed user
|
|
- Relay URL (optional): where to find this user
|
|
- Petname (optional): user's chosen name for contact
|
|
- Content may contain JSON relay list (deprecated, use NIP-65)
|
|
|
|
**Usage**:
|
|
- Clients fetch kind 3 to build following list
|
|
- Always replace old version with new
|
|
- Use for social graph discovery
|
|
|
|
### NIP-03: OpenTimestamps Attestations
|
|
|
|
**Status**: Optional
|
|
|
|
Allows embedding OpenTimestamps proofs in events.
|
|
|
|
**Format**:
|
|
```json
|
|
{
|
|
"tags": [
|
|
["ots", "<base64-ots-proof>"]
|
|
]
|
|
}
|
|
```
|
|
|
|
Used to prove an event existed at a specific time via Bitcoin blockchain timestamps.
|
|
|
|
### NIP-04: Encrypted Direct Messages
|
|
|
|
**Status**: Deprecated (use NIP-44)
|
|
|
|
Event kind `4` for encrypted private messages.
|
|
|
|
**Encryption**:
|
|
- ECDH shared secret between sender/receiver
|
|
- AES-256-CBC encryption
|
|
- Base64 encoded result
|
|
|
|
**Format**:
|
|
```json
|
|
{
|
|
"kind": 4,
|
|
"tags": [
|
|
["p", "<recipient-pubkey>"]
|
|
],
|
|
"content": "<encrypted-content>"
|
|
}
|
|
```
|
|
|
|
**Security Issues**:
|
|
- Vulnerable to certain attacks
|
|
- No forward secrecy
|
|
- Use NIP-44 instead
|
|
|
|
### NIP-05: Mapping Nostr Keys to DNS-based Internet Identifiers
|
|
|
|
**Status**: Widely implemented
|
|
|
|
Allows verification of identity via domain names (like email addresses).
|
|
|
|
**Format**: `name@domain.com`
|
|
|
|
**Implementation**:
|
|
|
|
1. User adds `"nip05": "alice@example.com"` to metadata (kind 0)
|
|
2. Domain serves `/.well-known/nostr.json`:
|
|
|
|
```json
|
|
{
|
|
"names": {
|
|
"alice": "<hex-pubkey>"
|
|
},
|
|
"relays": {
|
|
"<hex-pubkey>": ["wss://relay1.com", "wss://relay2.com"]
|
|
}
|
|
}
|
|
```
|
|
|
|
3. Clients verify by fetching and checking pubkey match
|
|
|
|
**Benefits**:
|
|
- Human-readable identifiers
|
|
- Domain-based verification
|
|
- Optional relay hints
|
|
- Spam prevention (verified users)
|
|
|
|
### NIP-06: Basic Key Derivation from Mnemonic Seed Phrase
|
|
|
|
**Status**: Optional
|
|
|
|
Derives Nostr keys from BIP39 mnemonic phrases.
|
|
|
|
**Derivation Path**: `m/44'/1237'/0'/0/0`
|
|
- 1237 is the coin type for Nostr
|
|
- Allows HD wallet-style key management
|
|
|
|
**Benefits**:
|
|
- Backup with 12/24 words
|
|
- Multiple accounts from one seed
|
|
- Compatible with BIP39 tools
|
|
|
|
### NIP-07: window.nostr Capability for Web Browsers
|
|
|
|
**Status**: Browser extension standard
|
|
|
|
Defines browser API for Nostr key management.
|
|
|
|
**API Methods**:
|
|
|
|
```javascript
|
|
window.nostr.getPublicKey(): Promise<pubkey>
|
|
window.nostr.signEvent(event): Promise<signedEvent>
|
|
window.nostr.getRelays(): Promise<{[url]: {read: boolean, write: boolean}}>
|
|
window.nostr.nip04.encrypt(pubkey, plaintext): Promise<ciphertext>
|
|
window.nostr.nip04.decrypt(pubkey, ciphertext): Promise<plaintext>
|
|
```
|
|
|
|
**Usage**:
|
|
- Web apps request signatures from extension
|
|
- Private keys never leave extension
|
|
- User approves each action
|
|
- Popular extensions: nos2x, Alby, Flamingo
|
|
|
|
### NIP-08: Handling Mentions
|
|
|
|
**Status**: Core convention
|
|
|
|
Defines how to mention users and events in notes.
|
|
|
|
**Format**:
|
|
- Add `p` or `e` tags for mentions
|
|
- Reference in content with `#[index]`
|
|
|
|
```json
|
|
{
|
|
"kind": 1,
|
|
"tags": [
|
|
["p", "<pubkey>", "<relay>"],
|
|
["e", "<event-id>", "<relay>"]
|
|
],
|
|
"content": "Hello #[0], check out #[1]"
|
|
}
|
|
```
|
|
|
|
Clients replace `#[0]`, `#[1]` with user-friendly displays.
|
|
|
|
### NIP-09: Event Deletion
|
|
|
|
**Status**: Widely implemented
|
|
|
|
Event kind `5` requests deletion of events.
|
|
|
|
**Format**:
|
|
```json
|
|
{
|
|
"kind": 5,
|
|
"tags": [
|
|
["e", "<event-id-to-delete>"],
|
|
["e", "<another-event-id>"]
|
|
],
|
|
"content": "Reason for deletion (optional)"
|
|
}
|
|
```
|
|
|
|
**Behavior**:
|
|
- Only author can delete their events
|
|
- Relays SHOULD delete referenced events
|
|
- Not guaranteed (relays may ignore)
|
|
- Some clients show deletion notice
|
|
|
|
### NIP-10: Text Note References (Reply, Threads)
|
|
|
|
**Status**: Core threading standard
|
|
|
|
Conventions for `e` and `p` tags in threaded conversations.
|
|
|
|
**Markers**:
|
|
- `root`: The root event of the thread
|
|
- `reply`: Direct parent being replied to
|
|
- `mention`: Mentioned but not replied to
|
|
|
|
**Format**:
|
|
```json
|
|
{
|
|
"kind": 1,
|
|
"tags": [
|
|
["e", "<root-event-id>", "<relay>", "root"],
|
|
["e", "<parent-event-id>", "<relay>", "reply"],
|
|
["e", "<mentioned-event-id>", "<relay>", "mention"],
|
|
["p", "<author1-pubkey>"],
|
|
["p", "<author2-pubkey>"]
|
|
]
|
|
}
|
|
```
|
|
|
|
**Best Practices**:
|
|
- Always include root marker for thread context
|
|
- Include reply marker for direct parent
|
|
- Add p tags for all mentioned users
|
|
- Maintains thread integrity
|
|
|
|
### NIP-11: Relay Information Document
|
|
|
|
**Status**: Standard
|
|
|
|
HTTP endpoint for relay metadata.
|
|
|
|
**Implementation**:
|
|
- HTTP GET to relay URL (not WebSocket)
|
|
- Accept header: `application/nostr+json`
|
|
|
|
**Response Example**:
|
|
```json
|
|
{
|
|
"name": "Example Relay",
|
|
"description": "A Nostr relay",
|
|
"pubkey": "<admin-pubkey>",
|
|
"contact": "admin@example.com",
|
|
"supported_nips": [1, 2, 9, 11, 12, 15, 16, 20, 22],
|
|
"software": "git+https://github.com/...",
|
|
"version": "1.0.0",
|
|
"limitation": {
|
|
"max_message_length": 16384,
|
|
"max_subscriptions": 20,
|
|
"max_filters": 100,
|
|
"max_limit": 5000,
|
|
"max_subid_length": 100,
|
|
"min_prefix": 4,
|
|
"max_event_tags": 100,
|
|
"max_content_length": 8196,
|
|
"min_pow_difficulty": 30,
|
|
"auth_required": false,
|
|
"payment_required": false
|
|
},
|
|
"relay_countries": ["US", "CA"],
|
|
"language_tags": ["en", "es"],
|
|
"tags": ["adult-content", "no-spam"],
|
|
"posting_policy": "https://example.com/policy",
|
|
"payments_url": "https://example.com/pay",
|
|
"fees": {
|
|
"admission": [{"amount": 5000000, "unit": "msats"}],
|
|
"subscription": [{"amount": 1000000, "unit": "msats", "period": 2592000}],
|
|
"publication": []
|
|
},
|
|
"icon": "https://example.com/icon.png"
|
|
}
|
|
```
|
|
|
|
**Usage**:
|
|
- Clients discover relay capabilities
|
|
- Check NIP support before using features
|
|
- Display relay info to users
|
|
- Respect limitations
|
|
|
|
### NIP-12: Generic Tag Queries
|
|
|
|
**Status**: Core functionality
|
|
|
|
Extends filtering to support any single-letter tag.
|
|
|
|
**Syntax**: `#<letter>: [<value>, ...]`
|
|
|
|
**Examples**:
|
|
```json
|
|
{
|
|
"#t": ["bitcoin", "nostr"],
|
|
"#p": ["pubkey1", "pubkey2"],
|
|
"#e": ["eventid1"]
|
|
}
|
|
```
|
|
|
|
Matches events with specified tag values.
|
|
|
|
### NIP-13: Proof of Work
|
|
|
|
**Status**: Spam prevention
|
|
|
|
Requires computational work for event publication.
|
|
|
|
**Implementation**:
|
|
- Add `nonce` tag: `["nonce", "<number>", "<target-difficulty>"]`
|
|
- Hash event ID until leading zero bits >= difficulty
|
|
- Increment nonce until condition met
|
|
|
|
**Example**:
|
|
```json
|
|
{
|
|
"tags": [
|
|
["nonce", "12345", "20"]
|
|
],
|
|
"id": "00000abcd..." // 20+ leading zero bits
|
|
}
|
|
```
|
|
|
|
**Difficulty Levels**:
|
|
- 0-10: Very easy
|
|
- 20: Moderate
|
|
- 30+: Difficult
|
|
- 40+: Very difficult
|
|
|
|
Relays can require minimum PoW for acceptance.
|
|
|
|
### NIP-14: Subject Tag
|
|
|
|
**Status**: Convenience
|
|
|
|
Adds `subject` tag for event titles/subjects.
|
|
|
|
**Format**:
|
|
```json
|
|
{
|
|
"tags": [
|
|
["subject", "My Post Title"]
|
|
]
|
|
}
|
|
```
|
|
|
|
Used for long-form content, discussions, emails-style messages.
|
|
|
|
### NIP-15: End of Stored Events (EOSE)
|
|
|
|
**Status**: Core protocol
|
|
|
|
Relay sends `EOSE` after sending all stored events matching a subscription.
|
|
|
|
**Format**: `["EOSE", <subscription_id>]`
|
|
|
|
**Usage**:
|
|
- Clients know when historical events are complete
|
|
- Can show "loading" state until EOSE
|
|
- New events after EOSE are real-time
|
|
|
|
### NIP-16: Event Treatment
|
|
|
|
**Status**: Event lifecycle
|
|
|
|
Defines three event categories:
|
|
|
|
1. **Regular Events** (1000-9999):
|
|
- Immutable
|
|
- All versions kept
|
|
- Examples: notes, reactions
|
|
|
|
2. **Replaceable Events** (10000-19999):
|
|
- Only latest kept
|
|
- Same author + kind → replace
|
|
- Examples: metadata, contacts
|
|
|
|
3. **Ephemeral Events** (20000-29999):
|
|
- Not stored
|
|
- Forwarded once
|
|
- Examples: typing indicators, presence
|
|
|
|
4. **Parameterized Replaceable Events** (30000-39999):
|
|
- Replaced based on `d` tag
|
|
- Same author + kind + d-tag → replace
|
|
- Examples: long-form posts, product listings
|
|
|
|
### NIP-18: Reposts
|
|
|
|
**Status**: Social feature
|
|
|
|
Event kind `6` for reposting/sharing events.
|
|
|
|
**Format**:
|
|
```json
|
|
{
|
|
"kind": 6,
|
|
"tags": [
|
|
["e", "<reposted-event-id>", "<relay>"],
|
|
["p", "<original-author-pubkey>"]
|
|
],
|
|
"content": "" // or reposted event JSON
|
|
}
|
|
```
|
|
|
|
**Generic Repost** (kind 16):
|
|
- Can repost any event kind
|
|
- Preserves original context
|
|
|
|
### NIP-19: bech32-encoded Entities
|
|
|
|
**Status**: Widely implemented
|
|
|
|
Human-readable encodings for Nostr entities.
|
|
|
|
**Formats**:
|
|
|
|
1. **npub**: Public key
|
|
- `npub1xyz...`
|
|
- Safer to share than hex
|
|
|
|
2. **nsec**: Private key (SENSITIVE!)
|
|
- `nsec1xyz...`
|
|
- Never share publicly
|
|
|
|
3. **note**: Event ID
|
|
- `note1xyz...`
|
|
- Links to specific events
|
|
|
|
4. **nprofile**: Profile with hints
|
|
- Includes pubkey + relay URLs
|
|
- Better discovery
|
|
|
|
5. **nevent**: Event with hints
|
|
- Includes event ID + relay URLs + author
|
|
- Reliable event fetching
|
|
|
|
6. **naddr**: Replaceable event coordinate
|
|
- Includes kind + pubkey + d-tag + relays
|
|
- For parameterized replaceable events
|
|
|
|
**Usage**:
|
|
- Use for sharing/displaying identifiers
|
|
- Clients should support all formats
|
|
- Always use npub/nsec instead of hex when possible
|
|
|
|
### NIP-20: Command Results
|
|
|
|
**Status**: Core protocol
|
|
|
|
Defines `OK` message format from relays.
|
|
|
|
**Format**: `["OK", <event_id>, <accepted>, <message>]`
|
|
|
|
**Examples**:
|
|
```json
|
|
["OK", "abc123...", true, ""]
|
|
["OK", "def456...", false, "invalid: signature verification failed"]
|
|
["OK", "ghi789...", false, "pow: difficulty too low"]
|
|
["OK", "jkl012...", false, "rate-limited: slow down"]
|
|
```
|
|
|
|
**Common Rejection Prefixes**:
|
|
- `duplicate:` - Event already received
|
|
- `pow:` - Insufficient proof of work
|
|
- `blocked:` - Pubkey or content blocked
|
|
- `rate-limited:` - Too many requests
|
|
- `invalid:` - Event validation failed
|
|
- `error:` - Server error
|
|
|
|
### NIP-21: nostr: URI Scheme
|
|
|
|
**Status**: Standard linking
|
|
|
|
Defines `nostr:` URI scheme for deep linking.
|
|
|
|
**Format**:
|
|
- `nostr:npub1...`
|
|
- `nostr:note1...`
|
|
- `nostr:nevent1...`
|
|
- `nostr:nprofile1...`
|
|
- `nostr:naddr1...`
|
|
|
|
**Usage**:
|
|
- Clickable links in web/mobile
|
|
- Cross-app navigation
|
|
- QR codes
|
|
|
|
### NIP-22: Event created_at Limits
|
|
|
|
**Status**: Relay policy
|
|
|
|
Relays may reject events with timestamps too far in past/future.
|
|
|
|
**Recommendations**:
|
|
- Reject events created_at > 15 minutes in future
|
|
- Reject very old events (relay-specific)
|
|
- Prevents timestamp manipulation
|
|
|
|
### NIP-23: Long-form Content
|
|
|
|
**Status**: Blog/article support
|
|
|
|
Event kind `30023` for long-form content (articles, blogs).
|
|
|
|
**Format**:
|
|
```json
|
|
{
|
|
"kind": 30023,
|
|
"tags": [
|
|
["d", "<unique-identifier>"],
|
|
["title", "Article Title"],
|
|
["summary", "Brief description"],
|
|
["published_at", "<unix-timestamp>"],
|
|
["t", "tag1"], ["t", "tag2"],
|
|
["image", "https://..."]
|
|
],
|
|
"content": "Markdown content..."
|
|
}
|
|
```
|
|
|
|
**Characteristics**:
|
|
- Parameterized replaceable (by `d` tag)
|
|
- Content in Markdown
|
|
- Rich metadata
|
|
- Can be edited (updates replace)
|
|
|
|
### NIP-25: Reactions
|
|
|
|
**Status**: Widely implemented
|
|
|
|
Event kind `7` for reactions to events (likes, emoji reactions).
|
|
|
|
**Format**:
|
|
```json
|
|
{
|
|
"kind": 7,
|
|
"tags": [
|
|
["e", "<reacted-event-id>"],
|
|
["p", "<event-author-pubkey>"],
|
|
["k", "<reacted-event-kind>"]
|
|
],
|
|
"content": "+" // or emoji
|
|
}
|
|
```
|
|
|
|
**Content Values**:
|
|
- `+`: Like/upvote
|
|
- `-`: Dislike (discouraged)
|
|
- Emoji: 👍, ❤️, 😂, etc.
|
|
- Custom reactions
|
|
|
|
**Client Display**:
|
|
- Count reactions per event
|
|
- Group by emoji
|
|
- Show who reacted
|
|
|
|
### NIP-26: Delegated Event Signing
|
|
|
|
**Status**: Advanced delegation
|
|
|
|
Allows delegating event signing to another key.
|
|
|
|
**Use Cases**:
|
|
- Bot accounts posting for user
|
|
- Temporary keys for devices
|
|
- Service providers posting on behalf
|
|
|
|
**Implementation**:
|
|
- Delegation token in tags
|
|
- Limits by kind, time range
|
|
- Original author still verifiable
|
|
|
|
### NIP-27: Text Note References
|
|
|
|
**Status**: Convenience
|
|
|
|
Shortcuts for mentioning entities inline.
|
|
|
|
**Format**:
|
|
- `nostr:npub1...` → user mention
|
|
- `nostr:note1...` → event reference
|
|
- `nostr:nevent1...` → event with context
|
|
|
|
Clients render as clickable links.
|
|
|
|
### NIP-28: Public Chat (Channels)
|
|
|
|
**Status**: Channel support
|
|
|
|
Event kinds for public chat channels.
|
|
|
|
**Event Kinds**:
|
|
- `40`: Create channel
|
|
- `41`: Set channel metadata
|
|
- `42`: Create message
|
|
- `43`: Hide message
|
|
- `44`: Mute user
|
|
|
|
**Channel Creation (kind 40)**:
|
|
```json
|
|
{
|
|
"kind": 40,
|
|
"content": "{\"name\": \"Bitcoin\", \"about\": \"Discussion\", \"picture\": \"url\"}"
|
|
}
|
|
```
|
|
|
|
**Channel Message (kind 42)**:
|
|
```json
|
|
{
|
|
"kind": 42,
|
|
"tags": [
|
|
["e", "<channel-id>", "<relay>", "root"]
|
|
],
|
|
"content": "Hello channel!"
|
|
}
|
|
```
|
|
|
|
### NIP-33: Parameterized Replaceable Events
|
|
|
|
**Status**: Core feature
|
|
|
|
Event kinds 30000-39999 are replaceable by `d` tag.
|
|
|
|
**Format**:
|
|
```json
|
|
{
|
|
"kind": 30000,
|
|
"tags": [
|
|
["d", "<identifier>"]
|
|
]
|
|
}
|
|
```
|
|
|
|
**Replacement Rule**:
|
|
- Same author + kind + d-tag → replace old event
|
|
- Different d-tag → separate events
|
|
- No d-tag → treated as `d` = ""
|
|
|
|
**Coordinate Reference**:
|
|
`<kind>:<pubkey>:<d-value>`
|
|
|
|
**Use Cases**:
|
|
- Product catalogs (each product = d-tag)
|
|
- Article revisions (article slug = d-tag)
|
|
- Configuration settings (setting name = d-tag)
|
|
|
|
### NIP-36: Sensitive Content Warning
|
|
|
|
**Status**: Content moderation
|
|
|
|
Tags for marking sensitive/NSFW content.
|
|
|
|
**Format**:
|
|
```json
|
|
{
|
|
"tags": [
|
|
["content-warning", "nudity"],
|
|
["content-warning", "violence"]
|
|
]
|
|
}
|
|
```
|
|
|
|
Clients can hide/blur until user confirms.
|
|
|
|
### NIP-39: External Identities
|
|
|
|
**Status**: Identity verification
|
|
|
|
Links Nostr identity to external platforms.
|
|
|
|
**Format (in kind 0 metadata)**:
|
|
```json
|
|
{
|
|
"kind": 0,
|
|
"content": "{\"identities\": [{\"platform\": \"github\", \"username\": \"alice\", \"proof\": \"url\"}]}"
|
|
}
|
|
```
|
|
|
|
**Supported Platforms**:
|
|
- GitHub
|
|
- Twitter
|
|
- Mastodon
|
|
- Matrix
|
|
- Telegram
|
|
|
|
### NIP-40: Expiration Timestamp
|
|
|
|
**Status**: Ephemeral content
|
|
|
|
Tag for auto-expiring events.
|
|
|
|
**Format**:
|
|
```json
|
|
{
|
|
"tags": [
|
|
["expiration", "<unix-timestamp>"]
|
|
]
|
|
}
|
|
```
|
|
|
|
Relays should delete event after expiration time.
|
|
|
|
### NIP-42: Authentication of Clients to Relays
|
|
|
|
**Status**: Access control
|
|
|
|
Relays can require client authentication.
|
|
|
|
**Flow**:
|
|
1. Relay sends: `["AUTH", "<challenge>"]`
|
|
2. Client creates kind `22242` event:
|
|
```json
|
|
{
|
|
"kind": 22242,
|
|
"tags": [
|
|
["relay", "<relay-url>"],
|
|
["challenge", "<challenge-string>"]
|
|
],
|
|
"created_at": <now>
|
|
}
|
|
```
|
|
3. Client sends: `["AUTH", <signed-event>]`
|
|
4. Relay verifies signature and challenge
|
|
|
|
**Benefits**:
|
|
- Spam prevention
|
|
- Access control
|
|
- Rate limiting per user
|
|
- Paid relays
|
|
|
|
### NIP-44: Encrypted Payloads (Versioned)
|
|
|
|
**Status**: Modern encryption
|
|
|
|
Improved encryption replacing NIP-04.
|
|
|
|
**Algorithm**:
|
|
- ECDH shared secret
|
|
- ChaCha20-Poly1305 AEAD
|
|
- Version byte for upgradability
|
|
- Salt for key derivation
|
|
|
|
**Security Improvements**:
|
|
- Authenticated encryption
|
|
- Better key derivation
|
|
- Version support
|
|
- Resistance to padding oracle attacks
|
|
|
|
**Format**:
|
|
```
|
|
<version-byte><encrypted-payload>
|
|
```
|
|
|
|
Base64 encode for `content` field.
|
|
|
|
### NIP-45: Event Counts
|
|
|
|
**Status**: Statistics
|
|
|
|
Request for event counts matching filters.
|
|
|
|
**Client Request**:
|
|
```json
|
|
["COUNT", <subscription_id>, <filters>]
|
|
```
|
|
|
|
**Relay Response**:
|
|
```json
|
|
["COUNT", <subscription_id>, {"count": 123, "approximate": false}]
|
|
```
|
|
|
|
**Usage**:
|
|
- Display follower counts
|
|
- Show engagement metrics
|
|
- Statistics dashboards
|
|
|
|
### NIP-46: Nostr Connect (Remote Signing)
|
|
|
|
**Status**: Remote signer protocol
|
|
|
|
Protocol for remote key management and signing.
|
|
|
|
**Architecture**:
|
|
- Signer: Holds private key
|
|
- Client: Requests signatures
|
|
- Communication via Nostr events
|
|
|
|
**Use Cases**:
|
|
- Mobile app delegates to desktop signer
|
|
- Browser extension as signer
|
|
- Hardware wallet integration
|
|
- Multi-device key sharing
|
|
|
|
### NIP-47: Wallet Connect
|
|
|
|
**Status**: Lightning integration
|
|
|
|
Protocol for connecting Lightning wallets to Nostr apps.
|
|
|
|
**Commands**:
|
|
- `pay_invoice`
|
|
- `get_balance`
|
|
- `get_info`
|
|
- `make_invoice`
|
|
- `lookup_invoice`
|
|
|
|
Enables in-app Lightning payments.
|
|
|
|
### NIP-50: Search Capability
|
|
|
|
**Status**: Optional
|
|
|
|
Full-text search in filter queries.
|
|
|
|
**Format**:
|
|
```json
|
|
{
|
|
"search": "bitcoin nostr"
|
|
}
|
|
```
|
|
|
|
**Implementation**:
|
|
- Relay-specific behavior
|
|
- May search content, tags, etc.
|
|
- Not standardized ranking
|
|
|
|
### NIP-51: Lists
|
|
|
|
**Status**: Curation
|
|
|
|
Event kinds for various list types.
|
|
|
|
**List Kinds**:
|
|
- `30000`: Categorized people list
|
|
- `30001`: Categorized bookmarks
|
|
- `10000`: Mute list
|
|
- `10001`: Pin list
|
|
|
|
**Format**:
|
|
```json
|
|
{
|
|
"kind": 30000,
|
|
"tags": [
|
|
["d", "my-list"],
|
|
["p", "<pubkey>", "<relay>", "<petname>"],
|
|
["t", "<category>"]
|
|
]
|
|
}
|
|
```
|
|
|
|
### NIP-56: Reporting
|
|
|
|
**Status**: Moderation
|
|
|
|
Event kind `1984` for reporting content.
|
|
|
|
**Format**:
|
|
```json
|
|
{
|
|
"kind": 1984,
|
|
"tags": [
|
|
["e", "<event-id>", "<relay>"],
|
|
["p", "<pubkey>"],
|
|
["report", "spam"] // or "nudity", "profanity", "illegal", "impersonation"
|
|
],
|
|
"content": "Additional details"
|
|
}
|
|
```
|
|
|
|
Used by relays and clients for moderation.
|
|
|
|
### NIP-57: Lightning Zaps
|
|
|
|
**Status**: Widely implemented
|
|
|
|
Protocol for Lightning tips with proof.
|
|
|
|
**Flow**:
|
|
1. Get user's Lightning address (from metadata)
|
|
2. Fetch LNURL data
|
|
3. Create zap request (kind `9734`)
|
|
4. Pay invoice
|
|
5. Relay publishes zap receipt (kind `9735`)
|
|
|
|
**Zap Request (kind 9734)**:
|
|
```json
|
|
{
|
|
"kind": 9734,
|
|
"tags": [
|
|
["p", "<recipient-pubkey>"],
|
|
["amount", "<millisats>"],
|
|
["relays", "relay1", "relay2"],
|
|
["e", "<event-id>"] // if zapping event
|
|
]
|
|
}
|
|
```
|
|
|
|
**Zap Receipt (kind 9735)**:
|
|
Published by LNURL provider, proves payment.
|
|
|
|
### NIP-58: Badges
|
|
|
|
**Status**: Reputation system
|
|
|
|
Award and display badges (achievements, credentials).
|
|
|
|
**Event Kinds**:
|
|
- `30008`: Badge definition
|
|
- `30009`: Profile badges
|
|
- `8`: Badge award
|
|
|
|
**Badge Definition**:
|
|
```json
|
|
{
|
|
"kind": 30008,
|
|
"tags": [
|
|
["d", "badge-id"],
|
|
["name", "Badge Name"],
|
|
["description", "What this means"],
|
|
["image", "url"],
|
|
["thumb", "thumbnail-url"]
|
|
]
|
|
}
|
|
```
|
|
|
|
### NIP-65: Relay List Metadata
|
|
|
|
**Status**: Critical for routing
|
|
|
|
Event kind `10002` for user's relay preferences.
|
|
|
|
**Format**:
|
|
```json
|
|
{
|
|
"kind": 10002,
|
|
"tags": [
|
|
["r", "wss://relay1.com"],
|
|
["r", "wss://relay2.com", "write"],
|
|
["r", "wss://relay3.com", "read"]
|
|
]
|
|
}
|
|
```
|
|
|
|
**Usage**:
|
|
- Clients discover where to fetch user's events (read)
|
|
- Clients know where to send events for user (write)
|
|
- Optimizes relay connections
|
|
- Reduces bandwidth
|
|
|
|
**Best Practice**:
|
|
- Always check NIP-65 before querying
|
|
- Fall back to NIP-05 relays if no NIP-65
|
|
- Cache relay lists
|
|
|
|
### NIP-78: App-Specific Data
|
|
|
|
**Status**: Application storage
|
|
|
|
Event kind `30078` for arbitrary app data.
|
|
|
|
**Format**:
|
|
```json
|
|
{
|
|
"kind": 30078,
|
|
"tags": [
|
|
["d", "<app-name>:<data-key>"]
|
|
],
|
|
"content": "<encrypted-or-public-data>"
|
|
}
|
|
```
|
|
|
|
**Use Cases**:
|
|
- App settings
|
|
- Client-specific cache
|
|
- User preferences
|
|
- Draft posts
|
|
|
|
### NIP-84: Highlights
|
|
|
|
**Status**: Annotation
|
|
|
|
Event kind `9802` for highlighting content.
|
|
|
|
**Format**:
|
|
```json
|
|
{
|
|
"kind": 9802,
|
|
"tags": [
|
|
["e", "<event-id>"],
|
|
["context", "surrounding text..."],
|
|
["a", "<article-coordinate>"]
|
|
],
|
|
"content": "highlighted portion"
|
|
}
|
|
```
|
|
|
|
Like a highlighter pen for web content.
|
|
|
|
### NIP-89: Application Handlers
|
|
|
|
**Status**: App discovery
|
|
|
|
Advertise and discover apps that handle specific event kinds.
|
|
|
|
**Format (kind 31989)**:
|
|
```json
|
|
{
|
|
"kind": 31989,
|
|
"tags": [
|
|
["k", "1"], // handles kind 1
|
|
["web", "https://app.com/<bech32>"],
|
|
["ios", "app-scheme://<bech32>"],
|
|
["android", "app-package://<bech32>"]
|
|
]
|
|
}
|
|
```
|
|
|
|
**Kind 31990**: User's preferred handlers
|
|
|
|
### NIP-94: File Metadata
|
|
|
|
**Status**: File sharing
|
|
|
|
Event kind `1063` for file metadata.
|
|
|
|
**Format**:
|
|
```json
|
|
{
|
|
"kind": 1063,
|
|
"tags": [
|
|
["url", "https://..."],
|
|
["m", "image/jpeg"], // MIME type
|
|
["x", "<sha256-hash>"],
|
|
["size", "123456"],
|
|
["dim", "1920x1080"],
|
|
["magnet", "magnet:..."],
|
|
["blurhash", "..."]
|
|
],
|
|
"content": "Description"
|
|
}
|
|
```
|
|
|
|
**Use Cases**:
|
|
- Images, videos, audio
|
|
- Documents
|
|
- Torrents
|
|
- IPFS files
|
|
|
|
### NIP-96: HTTP File Storage Integration
|
|
|
|
**Status**: File hosting
|
|
|
|
HTTP API for file uploads/downloads.
|
|
|
|
**Endpoints**:
|
|
- `GET /.well-known/nostr/nip96.json` - Server info
|
|
- `POST /upload` - Upload file
|
|
- `DELETE /delete` - Delete file
|
|
|
|
**Upload Response**:
|
|
Returns kind `1063` event data for the file.
|
|
|
|
### NIP-98: HTTP Auth
|
|
|
|
**Status**: API authentication
|
|
|
|
Use Nostr events for HTTP API auth.
|
|
|
|
**Flow**:
|
|
1. Create kind `27235` event with:
|
|
- `u` tag: API URL
|
|
- `method` tag: HTTP method
|
|
2. Add `Authorization: Nostr <base64-event>` header
|
|
3. Server verifies signature
|
|
|
|
**Benefits**:
|
|
- No passwords
|
|
- Cryptographic authentication
|
|
- Works with Nostr keys
|
|
|
|
## Summary of Key NIPs by Category
|
|
|
|
### Essential (All implementations)
|
|
- NIP-01, NIP-02, NIP-10, NIP-19
|
|
|
|
### Social Features
|
|
- NIP-25 (reactions), NIP-18 (reposts), NIP-23 (long-form), NIP-28 (channels)
|
|
|
|
### Identity & Discovery
|
|
- NIP-05 (verification), NIP-39 (external identities), NIP-65 (relay lists)
|
|
|
|
### Security & Privacy
|
|
- NIP-04 (deprecated encryption), NIP-44 (modern encryption), NIP-42 (auth), NIP-13 (PoW)
|
|
|
|
### Lightning Integration
|
|
- NIP-47 (wallet connect), NIP-57 (zaps)
|
|
|
|
### Content & Moderation
|
|
- NIP-56 (reporting), NIP-36 (content warnings), NIP-09 (deletion)
|
|
|
|
### Advanced Features
|
|
- NIP-33 (parameterized replaceable), NIP-46 (remote signing), NIP-50 (search)
|
|
|