The rstate REST API exposes relay intelligence aggregated from multiple independent NIP-66 monitors. All endpoints return JSON. The base URL for the hosted API isDocumentation Index
Fetch the complete documentation index at: https://mintlify.com/sandwichfarm/nostr-watch/llms.txt
Use this file to discover all available pages before exploring further.
https://api.nostr.watch/v2. When running rstate locally with REST_ENABLED=true, the default base URL is http://localhost:3000. Interactive OpenAPI documentation is available at /docs when the server is running.
Most endpoints are public and require no authentication. The only authenticated endpoint is
PUT /policy, which requires NIP-98 HTTP Auth.GET /health/ping
Returns server health, version, uptime, and cache statistics. Use this to verify the server is reachable and to inspect cache efficiency. Response:Overall server status. One of
ok (all connections healthy), degraded (partial connectivity), or error (no connections).Server software version.
Server uptime in seconds.
Total number of relay observations in the current dataset.
GET /relays
List all relays with pagination and sorting. Use theformat parameter to control response verbosity.
Query parameters:
Results per page. Default
50, maximum 200.Pagination offset. Default
0.Sort field. One of
url, updated, observationCount, or lastSeen. Default url.Sort direction.
asc or desc. Default asc.Response verbosity.
full includes per-monitor attribution, detailed returns aggregated values (default), simple returns URLs only.{ relays: [], total, limit, offset }
GET /relays/state
Get the aggregated state for a specific relay URL. Returns a single relay object or a 404 error if the relay is not in the dataset. Query parameters:Relay WebSocket URL, URL-encoded. Example:
wss%3A%2F%2Frelay.damus.ioResponse verbosity.
full, detailed (default), or simple.{ relay: {} } or 404 with { error: { code: "RELAY_NOT_FOUND", message } }
POST /relays/search
Filter relays using one or more criteria. All filter fields are optional — only relays matching all provided filters are returned. Request body:Network type filter. One of
clearnet, tor, i2p, or hybrid.Return only relays that support all listed NIP numbers. Example:
[1, 42].Array of
{ namespace, value } label filters. Example: [{ "namespace": "country", "value": "US" }].Minimum monitor support ratio (0–1). Only include relays confirmed by at least this fraction of monitors. Example:
0.7.Results per page. Default
100.Pagination offset. Default
0.Response verbosity.
full, detailed (default), or simple.{ relays: [], total, limit, offset }
GET /relays/nearby
Find relays near a geographic coordinate using Haversine distance. Relay location is derived from the geohash (g tag) in NIP-66 events.
Query parameters:
Latitude, -90 to 90.
Longitude, -180 to 180.
Search radius in km. Default
100.Response verbosity.
full, detailed (default), or simple.{ relays: [], center: { lat, lon }, radius } — each relay object includes a distance field in km.
GET /relays/by/software
Group all relays by their software family (from the NIP-11 info document). Returns counts and relay lists per software family. Pass thefamily query parameter to filter down to a single family.
Query parameters:
Filter to a specific software family name, e.g.
strfry. Omit to get all groups.{ groups: { family: [relayUrls] } }
Response (with filter): { relays: [relayUrls], total }
GET /relays/by/network
Group relays by network type (clearnet, tor, i2p).
Response: { groups: [{ network, count, relays }] }
GET /relays/by/nip
Group relays by which NIPs they support. Use thenip parameter to filter to a single NIP, and minSupport to exclude NIP support with low monitor agreement.
Query parameters:
Filter to a specific NIP number (e.g.
42). Omit to get all NIP groups.Minimum monitor support ratio (0–1). Default
0.5.{ groups: [{ nip, count, avgSupport, relays }] }
GET /relays/by/country
Group relays by country. Relay country is derived from geo label data. Pass thecountryCode parameter to filter to a specific country.
Query parameters:
ISO 3166-1 alpha-2 country code (e.g.
US, DE). Omit to get all countries.{ groups: [{ countryCode, countryName, count, relays }] }
POST /relays/compare
Compare 1–10 relay URLs side by side. Returns full state objects for each relay plus a diff highlighting shared and differing properties. Request body:Array of 1–10 relay WebSocket URLs to compare.
Full relay state objects for each requested URL.
NIP numbers supported by all compared relays.
R tag values shared by all relays (e.g.
!auth, !payment).Booleans indicating where the relays differ:
network, software, latency.Error responses
All error responses follow a consistent format:| HTTP status | Code | Meaning |
|---|---|---|
| 400 | VALIDATION_ERROR | Invalid request parameters |
| 404 | RELAY_NOT_FOUND | Relay URL not in the dataset |
| 429 | RATE_LIMITED | Too many requests — check the Retry-After header |
| 500 | INTERNAL_ERROR | Server error |