1 Overview
A relay operator needs day-to-day controls: ban a spammer, approve a reported event, block an abusive IP, rename the relay. This NIP defines a management API for those tasks. A relay may implement it. Support is optional.
The API is a request-response protocol over HTTP. It is not part of the NIP-01 WebSocket flow. It lives on the same URI as the relay's WebSocket endpoint. A special Content-Type header tells the relay that an HTTP request is a management call, not a WebSocket upgrade.
The protocol defines 25 methods. A management client first calls supportedmethods to discover what the relay implements. Every call must carry a signed NIP-98 authorization event, so only authorized keys can manage the relay.
This API is for relay operators and moderators, not for regular users. A normal client never needs it. If you build a relay dashboard, this chapter is your control panel wiring diagram.
2 Transport and Message Format
The relay watches for HTTP or HTTPS requests with the header Content-Type: application/nostr+json+rpc on a URI that supports WebSocket upgrades. When such a request arrives, the relay parses the body as a JSON document with two fields:
{
"method": <method-name>,
"params": [<array>, <of>, <parameters>]
}
The relay then returns a JSON response with this shape:
{
"result": <arbitrary value — shape depends on the method>,
"error": <optional error message, present if the call has errored>
}
| Field | Direction | Rule |
|---|---|---|
| method | request | The name of the method to call. One of the 25 names in §3. |
| params | request | An array of positional parameters. May be empty. |
| result | response | The return value. Each method defines its own shape. |
| error | response | An optional error message string. Present when the call fails. |
3 The Methods
The tables below list every method a relay may support. Params are positional. Unless noted, a write method returns result: true — a boolean always set to true. List methods return arrays. A relay may support any subset; report the subset with supportedmethods.
Discovery
| Method | Params | Result |
|---|---|---|
| supportedmethods | [] | ["<method-name>", …] — an array with the names of all the other supported methods. |
Pubkey moderation
A ban rejects a pubkey. An allow whitelists a pubkey. The reason parameter is an optional free-text string.
| Method | Params | Result |
|---|---|---|
| banpubkey | ["<32-byte-hex-public-key>", "<optional-reason>"] | true |
| unbanpubkey | ["<32-byte-hex-public-key>", "<optional-reason>"] | true |
| listbannedpubkeys | [] | [{"pubkey": "<32-byte-hex>", "reason": "<optional-reason>"}, …] — an array of objects. |
| allowpubkey | ["<32-byte-hex-public-key>", "<optional-reason>"] | true |
| unallowpubkey | ["<32-byte-hex-public-key>", "<optional-reason>"] | true |
| listallowedpubkeys | [] | [{"pubkey": "<32-byte-hex>", "reason": "<optional-reason>"}, …] — an array of objects. |
Roles
A role is a named label a relay can attach to a pubkey, for example "moderator". A role has an id, a display label, a description, a color, and a sort order.
| Method | Params | Result |
|---|---|---|
| createrole | [id, label, description, color, order] | true |
| editrole | [id, label, description, color, order] | true |
| deleterole | [id] | true |
| assignrole | ["<32-byte-hex-public-key>", "<role-id>"] | true |
| unassignrole | ["<32-byte-hex-public-key>", "<role-id>"] | true |
The spec leaves gaps here. The role params have no defined types or formats: the shape of color and the semantics of order are unstated. There is no method to list roles or role assignments. Also, unbanpubkey and unallowpubkey take an optional reason with no stated use, while unblockip takes none. Expect implementations to differ.
Event moderation
These methods work a moderation queue. The relay collects reported or held events. A moderator lists them, then allows or bans each one by event id.
| Method | Params | Result |
|---|---|---|
| listeventsneedingmoderation | [] | [{"id": "<32-byte-hex>", "reason": "<optional-reason>"}] — an array of objects. |
| allowevent | ["<32-byte-hex-event-id>", "<optional-reason>"] | true |
| banevent | ["<32-byte-hex-event-id>", "<optional-reason>"] | true |
| listbannedevents | [] | [{"id": "<32-byte hex>", "reason": "<optional-reason>"}, …] — an array of objects. |
Relay profile
These methods edit the relay's public identity. Clients read that identity through the NIP-11 relay information document.
| Method | Params | Result |
|---|---|---|
| changerelayname | ["<new-name>"] | true |
| changerelaydescription | ["<new-description>"] | true |
| changerelayicon | ["<new-icon-url>"] | true |
Kind policy
These methods control which event kinds the relay accepts. The kind number is a bare JSON number, not a string.
| Method | Params | Result |
|---|---|---|
| allowkind | [<kind-number>] | true |
| disallowkind | [<kind-number>] | true |
| listallowedkinds | [] | [<kind-number>, …] — an array of numbers. |
IP blocking
| Method | Params | Result |
|---|---|---|
| blockip | ["<ip-address>", "<optional-reason>"] | true |
| unblockip | ["<ip-address>"] | true |
| listblockedips | [] | [{"ip": "<ip-address>", "reason": "<optional-reason>"}, …] — an array of objects. |
4 Authorization
Every request must contain an Authorization header with a valid NIP-98 event. Two adjustments apply on top of NIP-98:
- The
payloadtag is required, not optional. It carries the sha256 hash of the request body, so the relay can verify the RPC call was not altered. - The
utag is the relay URL.
If the Authorization header is missing or invalid, the endpoint should return a 401 response.
Authorization is not the same as permission. NIP-98 proves who signed the request. The relay still decides which pubkeys may call which methods. That policy is up to the relay operator; this NIP does not define it.
5 Worked Example
A moderator discovers the relay's methods, bans a spammer, and confirms the ban. Orange lines go to the relay. Blue lines come from the relay.
-- discover what the relay supports -- → POST / HTTP/1.1 Content-Type: application/nostr+json+rpc Authorization: Nostr eyJpZCI6IjVjODNkYTc3… → {"method":"supportedmethods","params":[]} ← {"result":["banpubkey","unbanpubkey","listbannedpubkeys","allowkind"]} -- ban a spammer (each call repeats the headers above) -- → {"method":"banpubkey", "params":["22a12a128a3be27cd7fb250cbe796e692896398dc1440ae3fa567812c8107c1c", "spam"]} ← {"result":true} -- confirm -- → {"method":"listbannedpubkeys","params":[]} ← {"result":[{"pubkey":"22a12a128a3be27cd7fb250cbe796e692896398dc1440ae3fa567812c8107c1c", "reason":"spam"}]} -- a failed call and a missing Authorization header -- ← {"error":"method not supported"} ← HTTP/1.1 401 Unauthorized
6 Version History
NIP-86 arrived in late 2024 and has grown by small additions. Notable changes, newest first:
- 20262026-06Added the role methods:
createrole,editrole,deleterole,assignrole,unassignrole. - 20262026-06A
signeventmethod was added, then reverted one day later. It is not part of the spec. - 20262026-02Added
unbanpubkeyandunallowpubkey, so bans and allows can be undone. - Origin2024-11fiatjaf added NIP-86 with the initial method set, transport rules, and NIP-98 authorization.
Original Proposal - Credits
| Author | fiatjaf |
| First commit | 2024-11-25 — “add NIP-86: Relay Management API” (PR #1325) |
| Status | draft - optional — relays may implement any subset of the methods |
| Source | 86.md on GitHub - full change history |
7 See Also
- NIP-98 — the HTTP Auth event that every management call must carry.
- NIP-01 — the base protocol; defines events, kinds, pubkeys, and the WebSocket endpoint this API shares.
- NIP-11 — the relay information document that exposes the name, description, and icon these methods change.
- NIP-42 — client authentication inside the WebSocket connection; a different mechanism for a different layer.