{
    "meta": {
        "title": "D-Central — Nostr Relay Protocol Reference (NIP-01)",
        "description": "The 8 NIP-01 client<->relay wire messages (EVENT/REQ/CLOSE, EVENT/OK/EOSE/CLOSED/NOTICE) with JSON syntax and purpose. Companion tables cover the REQ filter fields and the standardized OK/CLOSED prefixes.",
        "generated": "2026-07-26T13:16:59+00:00",
        "version": "1.0",
        "as_of": "2026-07-26",
        "license": "https://creativecommons.org/licenses/by/4.0/",
        "license_name": "CC BY 4.0",
        "source": "https://d-central.tech/nostr-relay-protocol-reference/",
        "method": "Extracted from the canonical nostr-protocol/nips NIP-01 (01.md, raw, fetched 2026-07-26). Message syntax and purpose are faithful to the spec text. AUTH (NIP-42) is deliberately excluded as it is not part of NIP-01.",
        "provenance": "nostr-protocol/nips (github.com/nostr-protocol/nips) NIP-01.",
        "record_count": 8
    },
    "rows": [
        {
            "msg": "EVENT",
            "direction": "client->relay",
            "syntax": "[\"EVENT\", <event JSON>]",
            "purpose": "Publishes an event to the relay. The event is the full signed object (id, pubkey, created_at, kind, tags, content, sig)."
        },
        {
            "msg": "REQ",
            "direction": "client->relay",
            "syntax": "[\"REQ\", <subscription_id>, <filters1>, <filters2>, ...]",
            "purpose": "Requests stored events and subscribes to new ones. subscription_id is an arbitrary non-empty string up to 64 chars, scoped per connection; a new REQ with the same id replaces the old subscription."
        },
        {
            "msg": "CLOSE",
            "direction": "client->relay",
            "syntax": "[\"CLOSE\", <subscription_id>]",
            "purpose": "Stops a previously opened subscription identified by subscription_id."
        },
        {
            "msg": "EVENT",
            "direction": "relay->client",
            "syntax": "[\"EVENT\", <subscription_id>, <event JSON>]",
            "purpose": "Sends an event matching a subscription. MUST carry a subscription_id from a REQ the client previously opened."
        },
        {
            "msg": "OK",
            "direction": "relay->client",
            "syntax": "[\"OK\", <event_id>, <true|false>, <message>]",
            "purpose": "Reports acceptance (true) or rejection (false) of a client EVENT. The 4th parameter MUST be present; it MAY be empty when true, otherwise MUST be a machine-readable prefix + ':' + human message."
        },
        {
            "msg": "EOSE",
            "direction": "relay->client",
            "syntax": "[\"EOSE\", <subscription_id>]",
            "purpose": "End Of Stored Events: marks the boundary between stored events and real-time events newly streamed for that subscription."
        },
        {
            "msg": "CLOSED",
            "direction": "relay->client",
            "syntax": "[\"CLOSED\", <subscription_id>, <message>]",
            "purpose": "Sent when the relay refuses or terminates a subscription from its side. Uses the same prefix:message convention as OK."
        },
        {
            "msg": "NOTICE",
            "direction": "relay->client",
            "syntax": "[\"NOTICE\", <message>]",
            "purpose": "Sends a human-readable message (usually an error) to the client. NIP-01 defines no rules for how NOTICEs are sent or handled."
        }
    ],
    "filter_fields": [
        {
            "field": "ids",
            "type": "array of strings",
            "meaning": "Event ids to match. MUST contain exact 64-char lowercase hex (exact match; no prefix matching in current NIP-01)."
        },
        {
            "field": "authors",
            "type": "array of strings",
            "meaning": "The event pubkey must be one of these. MUST contain exact 64-char lowercase hex."
        },
        {
            "field": "kinds",
            "type": "array of integers",
            "meaning": "The event kind must be in the list."
        },
        {
            "field": "#&lt;single-letter&gt;",
            "type": "array of strings",
            "meaning": "Tag filter (e.g. #e = event ids, #p = pubkeys). Relays index single-letter tags; only the FIRST value of a tag is indexed. #e/#p MUST use exact 64-char lowercase hex. Event and filter must share at least one value."
        },
        {
            "field": "since",
            "type": "integer (unix seconds)",
            "meaning": "Event created_at must be >= since."
        },
        {
            "field": "until",
            "type": "integer (unix seconds)",
            "meaning": "Event created_at must be <= until. In short: since <= created_at <= until."
        },
        {
            "field": "limit",
            "type": "integer",
            "meaning": "Max events the relay SHOULD return for the initial query only (ignored afterwards). Returns the newest n by created_at (ties broken by lowest id)."
        }
    ],
    "ok_closed_prefixes": [
        {
            "prefix": "duplicate",
            "meaning": "The event was already received / stored."
        },
        {
            "prefix": "pow",
            "meaning": "The event does not meet a required proof-of-work difficulty."
        },
        {
            "prefix": "blocked",
            "meaning": "The pubkey or event is blocked by relay policy."
        },
        {
            "prefix": "rate-limited",
            "meaning": "The client is sending too fast."
        },
        {
            "prefix": "invalid",
            "meaning": "The event or request is malformed / fails validation."
        },
        {
            "prefix": "restricted",
            "meaning": "The action requires an authorization the client does not have."
        },
        {
            "prefix": "mute",
            "meaning": "The event was accepted-but-ignored (e.g. nobody was listening)."
        },
        {
            "prefix": "error",
            "meaning": "Catch-all for when none of the other prefixes fit."
        }
    ]
}