Chapter 11 - Relay Ops
11
Nostr Implementation Possibility - Hex № 11

Relay Information Document

A small JSON document a relay hands out over plain HTTP: its name, its limits, the NIPs it supports, and how to pay it.

1 Overview

A client needs to know things about a relay before it trusts it. Does the relay accept large events? Does it require payment? Which NIPs does it support? This NIP answers those questions.

A relay may publish a relay information document. This is a JSON object that describes the relay. Clients fetch it with a plain HTTP request, at the exact same URI they use for the relay's WebSocket connection.

The document is optional field by field. A relay fills in only what it wants to share. A client must ignore any field it does not recognize, so the format can grow without breaking old clients.

Hint!

Think of this document as a relay's box art and spec sheet. Read it before you connect, so your client can set expectations for message size, payment, and authentication ahead of time.

Client Relay GET / — Accept: application/nostr+json 200 OK — JSON information document
Fig. 11-1 — The fetch flow. One plain HTTP request and response. No WebSocket upgrade, no signed event.

2 Fetching the Document

A relay exposes one WebSocket URI, as defined in NIP-01. The information document lives at that same URI. A client asks for it with an ordinary HTTP or HTTPS request, not a WebSocket upgrade.

The client sets one required header:

Request requirement
HeaderValuePurpose
Acceptapplication/nostr+jsonTells the relay this is a request for the information document, not a WebSocket upgrade.

When a relay receives a matching request, it should return the JSON document below.

Wire format - relay information document
{
  "name":             <string identifying the relay>
  "description":      <string with detailed information>
  "banner":           <link to a banner image, .jpg or .png>
  "icon":             <link to a square icon image>
  "pubkey":           <administrative contact pubkey>
  "self":             <relay's own pubkey>
  "contact":          <administrative alternate contact>
  "supported_nips":   <list of NIP numbers supported by the relay>
  "software":         <string identifying relay software, a URL>
  "version":          <string version identifier>
  "terms_of_service": <link to a terms of service document>
}

Any field may be omitted. A client must ignore any field in the response it does not understand. This keeps old clients working when new fields are added later.

Warning!

A relay must accept CORS requests. It must send the Access-Control-Allow-Origin, Access-Control-Allow-Headers, and Access-Control-Allow-Methods headers. Without these, a web-based client cannot fetch the document from a browser.

3 Top-Level Fields

Ten fields describe the relay itself, its operator, and its software. All are optional strings, URLs, or a pubkey, unless noted otherwise.

Top-level field reference
FieldTypeRule
namestringShort relay name for client UI. Keep it under 30 characters, or a client may truncate it.
descriptionstringPlain-text detail about the relay. Use no markup and no line-wrap formatting. Separate paragraphs with a blank line. No length limit.
bannerURLLink to a banner image, in .jpg or .png format. Shows the relay's brand to non-technical users.
iconURLLink to a compact icon image. Used in tight UI spaces, such as a relay-list view. A square image is recommended.
pubkeyhex pubkey, 64 charsAdministrative contact. A client may send this pubkey an encrypted direct message (NIP-17) to report abuse, file a bug, or ask for help. The operator has no obligation to reply.
selfhex pubkey, 64 charsThe relay's own identity, kept separate from its administrator. The relay may respond using events published under this key.
contactstringAlternate contact, for the same purpose as pubkey. Should be a URI, such as a mailto: or https: link. A Nostr DM to pubkey is the preferred method.
supported_nipsarray of integersNIP numbers the relay implements, for example [1, 9, 11]. Do not advertise NIPs that are client-side only. Clients may ignore this field.
softwareURLLink to the relay software's project homepage.
versionstringSoftware version or commit identifier. The format is defined by the relay implementation.
terms_of_serviceURLLink to a terms-of-service document.

pubkey vs. self vs. contact

These three fields look similar but answer different questions. pubkey identifies a human administrator to message. self identifies the relay software acting as its own Nostr identity. contact is a fallback address, such as an email link, for when a Nostr DM is not practical.

4 Server Limitations

The limitation object lists practical limits the relay enforces. A client should expect a request that exceeds these limits to be rejected or to fail immediately.

limitation object - sub-fields
FieldTypeRule
max_message_lengthintegerMax bytes of incoming JSON the relay will decode and act on. Measured on the UTF-8 serialized string, from [ to ]. This is also the WebSocket frame size limit, and it caps the maximum event size.
max_subscriptionsintegerMax number of active subscriptions on one connection. An authenticated client with a paid relationship to the relay may get a higher limit.
max_limitintegerThe relay clamps every filter's limit value to this number, usually silently. Narrow the filter's time range to check for more results beyond it.
max_subid_lengthintegerMax length of a subscription ID string.
max_event_tagsintegerMax number of elements in an event's tags array.
max_content_lengthintegerMax Unicode characters in an event's content field. After JSON encoding the byte count may be larger, and max_message_length still applies.
min_pow_difficultyintegerMinimum proof-of-work difficulty (NIP-13) required on new events. The relay rejects events below this difficulty.
auth_requiredbooleanThe relay requires NIP-42 authentication before a new connection may do anything else. Even when false, specific actions may still require it.
payment_requiredbooleanThe relay requires payment before a new connection may perform any action.
restricted_writesbooleanThe relay requires some condition before it accepts events — for example a pubkey allow-list, or a specific kind. Set this only when clients are expected to know the policy in advance. Ordinary anti-spam heuristics do not qualify.
created_at_lower_limitintegerLower bound accepted for an event's created_at timestamp.
created_at_upper_limitintegerUpper bound accepted for an event's created_at timestamp.
default_limitintegerNumber of events the relay returns for a filter sent without a limit attribute.
Tech Note

Earlier drafts of this NIP also defined retention, relay_countries, language_tags, a content-classification tags field, and posting_policy. A 2026-02-14 revision, titled in the source history "partially remove bloat that no one cares about," dropped all five from the specification. The current 11.md does not define them, so this manual does not document them as active fields. See §7 Version History.

5 Pay-to-Relay

A relay that requires payment may publish its fee schedule so clients can display it.

Pay-to-relay fields
FieldTypeRule
payments_urlURLPage where a user can pay the relay.
fees.admissionarray of {amount, unit}One-time cost to join the relay.
fees.subscriptionarray of {amount, unit, period}Recurring cost. period is the billing interval, in seconds.
fees.publicationarray of {kinds, amount, unit}Cost to publish specific event kinds. kinds lists the kind numbers the fee applies to.
Example - fees object
{
  "payments_url": "https://relay.example.com/payments",
  "fees": {
    "admission":     [{ "amount": 1000000, "unit": "msats" }],
    "subscription": [{ "amount": 5000000, "unit": "msats", "period": 2592000 }],
    "publication":  [{ "kinds": [4], "amount": 100, "unit": "msats" }]
  }
}
Client Relay one URI, wss://relay… WebSocket NIP-01 event flow Info document this NIP, NIP-11 Upgrade: websocket Accept: nostr+json
Fig. 11-2 — One URI, two protocols. The relay tells the two requests apart by header, not by path.

6 Worked Example

The transcript below shows a full round trip: the HTTP request with the required header, and the JSON response. Orange lines go to the relay. Blue lines come from the relay.

HTTP session - https://relay.example.com
-- Client requests the information document --
→ GET / HTTP/1.1
→ Host: relay.example.com
→ Accept: application/nostr+json

-- Relay responds --
← HTTP/1.1 200 OK
← Content-Type: application/nostr+json
← Access-Control-Allow-Origin: *
← Access-Control-Allow-Headers: *
← Access-Control-Allow-Methods: GET
←
← {
    "name": "wine relay",
    "description": "A paid nostr relay for wine enthusiasts and everyone else.",
    "pubkey": "4918eb332a41b71ba9a74b1dc64276cfff592e55107b93baae38af3520e5597",
    "contact": "wino@relay.example.com",
    "supported_nips": [1, 2, 4, 9, 11, 40, 42, 50, 70, 77],
    "software": "https://git.example.com/relay-software",
    "version": "0.3.3",
    "terms_of_service": "https://relay.example.com/terms",
    "limitation": {
      "max_message_length": 524288,
      "max_subscriptions": 50,
      "max_limit": 1000,
      "max_subid_length": 71,
      "max_event_tags": 4000,
      "auth_required": false,
      "payment_required": true,
      "restricted_writes": true,
      "created_at_lower_limit": 94608000,
      "created_at_upper_limit": 300
    },
    "payments_url": "https://relay.example.com/invoices",
    "fees": {
      "admission": [{ "amount": 18888000, "unit": "msats" }]
    }
  }

A relay with a smaller feature set may return far fewer fields. This response is still valid:

Example - minimal information document
{
  "name": "a small free relay",
  "pubkey": "52b4a076bcbbbdc3a1aefa3735816cf74993b1b8db202b01c883c58be7fad8b",
  "software": "NFDB",
  "supported_nips": [1, 2, 9, 11, 40],
  "version": "1.0.0",
  "limitation": { "payment_required": false, "auth_required": false }
}

7 Version History

Notable changes to NIP-11, newest first:

  • 20262026-06-13Reformatted every code fence in the document from jsonc to yaml, repo-wide.
  • 20262026-02-14Removed retention, relay_countries, language_tags, the content-classification tags field, and posting_policy as unused "bloat."
  • 20252025-11-17Added the self field, letting a relay maintain an identity independent from its administrator.
  • 20252025-04-21Added terms_of_service, alongside a privacy-policy field later removed in the 2026-02-14 cleanup.
  • 20252025-04-13Removed an older max-filters mechanism; added max_limit and default_limit, and refreshed the worked examples.
  • 20242024-11-04Added the banner field, and renamed the earlier image field to icon.
  • 20232023-11-18Added restricted_writes to limitation, and clarified it excludes ordinary anti-spam heuristics.
  • 20232023-08-20Removed a min_prefix mention after prefix search was dropped from NIP-01; added created_at lower/upper limits to limitation.
  • 20232023-03-18nostr.wine proposed the extensions that became limitation and fees: server limits and a pay-to-relay fee schedule.
  • 20222022-11-23Made CORS support mandatory: relays must answer CORS preflight requests.
  • Origin2022-05-01fiatjaf published the first version in the newly migrated nostr-protocol/nips repository.

Original Proposal - Credits

Authorfiatjaf
First commit2022-05-01 — “migrate nips from main nostr repo.”
Statusdraft optional — a relay may implement it; nothing in NIP-01 requires it
Source11.md on GitHub - full change history

8 See Also

  • NIP-01 — defines the WebSocket URI this document is fetched from, and the base event/filter protocol it describes.
  • NIP-13 — proof of work; source of the difficulty number in min_pow_difficulty.
  • NIP-17 — private direct messages; how a client reaches the relay operator at its pubkey field.
  • NIP-42 — client authentication; what auth_required is asking for.
  • NIP-65 — relay list metadata; how a user tells others which relays to use, a separate concern from what one relay reports about itself.
  • NIP-86 — relay management API; a read/write control channel, compared to this read-only information document.