REST API

Read-only HTTP API for querying stored events at GET /api/v1/... — served on the same port as the WebSocket relay.

Base URL

The API is served under /api/v1 on the same port as the WebSocket relay:

text
http://<host>:<port>/api/v1/{identifier}
http://<host>:<port>/api/v1/{identifier}/{kind}

Host routing (server.api_host)

When server.api_host (e.g. api.example.com) is configured, the API and the relay are split by the Host header: api.example.com gets /api/v1, /health and /metrics; any other host gets the WebSocket relay and NIP-11. Without api_host the API is served on every host. Only GET is supported — WebSocket upgrade requests to /api/v1 are refused with 403.

Endpoints

Identifier-based paths

PathReturns
GET /api/v1/<npub1...>Latest kind-0 profile event
GET /api/v1/<note1> / <nevent1>The single event with this id
GET /api/v1/<naddr1>Events of the address (kind + author + d tag)
GET /api/v1/<npub1...>/<kind>Events by pubkey, filtered by kind (only valid for npub1...; 400 otherwise)

Query and aggregate endpoints

  • GET /api/v1/query — generic filter query without an identifier.
  • GET /api/v1/count — total count for the same filter parameters (NIP-45 semantics).
  • GET /api/v1/<npub1...>/kinds — per-kind event counts for an author, most used first.
  • GET /api/v1/<npub1...>/<kind>/daily — per-day counts for one month; month must be 1-12, and every day is reported zero-filled through the last day.
  • GET /api/v1/ids/<hex> — a single event by its 64-hex id (prefixes rejected).
  • GET /api/v1/<npub1...>/stats — author summary (total, first/last activity, kind breakdown).
  • GET /api/v1/<npub1...>/<kind>/hourly — per-hour counts for one day; all 24 hours are reported, zero-filled.
  • GET /api/v1/ids/<hex>/related — replies (#e) and quotes (#q) referencing the event.
  • GET /api/v1/<npub1...>/follows — the author's latest kind-3 follow list.
  • GET /api/v1/relay/kinds — the most common kinds on the relay (bounded, visibility-filtered sample).
  • GET /api/v1/relay/top-authors — the most active authors on the relay (bounded, visibility-filtered sample; approximate flag).
  • GET /api/v1/<npub1...>/relays — the author's latest NIP-65 relay list (kind 10002).
  • GET /api/v1/<npub1...>/<kind>/monthly — per-month counts, zero-filled over the since/until range (default: the whole period; capped at 120 months).

Query parameters

ParameterDescription
limitMax results (default 100, capped by max_api_limit)
offsetNumber of visible results to skip (pagination)
sinceOnly events with created_at >= since
untilOnly events with created_at <= until
sortasc/ascending for oldest first; default is newest first
searchNIP-50 full-text search (whole-word matching)
e / p / t / dFilter by #e / #p / #t / #d tags
no_p / no_e / no_t / no_dExclude events carrying that tag — applied before pagination, so excluded events never consume limit slots or offset steps

Response format

Successful responses return 200 OK with the following JSON body:

json
{
  "events": [
    {
      "id": "32-byte hex event id",
      "pubkey": "32-byte hex pubkey",
      "created_at": 1700000000,
      "kind": 1,
      "tags": [["t", "example"]],
      "content": "hello",
      "sig": "64-byte hex signature"
    }
  ],
  "count": 1,
  "more": false
}
FieldDescription
eventsThe events of this page (newest first by default)
countThe number of events in this page
moreTrue when further pages exist (use offset to fetch them)

Pagination

Pagination is done with offset and the more flag, computed over the visible sequence — hidden events never skip or duplicate a page:

sh
curl "http://127.0.0.1:8080/api/v1/npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkws3w8ktc/1?limit=50&offset=0"     # page 1
curl "http://127.0.0.1:8080/api/v1/npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkws3w8ktc/1?limit=50&offset=50"    # page 2 (when more was true)

Visibility rules

The API is unauthenticated, so it withholds the same events as an anonymous WebSocket connection:

  • NIP-70 protected events (carrying a - tag)
  • NIP-59 gift wraps (kind 1059)
  • NIP-29 private/hidden group content (visible only to members)

Errors and status codes

CodeMeaning
200Success
400Invalid identifier or query parameter
403WebSocket upgrade attempt to /api/v1
404Unknown path, or wrong Host for the API (api_host configured)
503API concurrency limit reached — retry shortly

Examples

Fetch a user's notes (newest first):

sh
curl "http://127.0.0.1:8080/api/v1/npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkws3w8ktc/1"

Paginate and sort:

sh
curl "http://127.0.0.1:8080/api/v1/npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkws3w8ktc/1?limit=10&offset=10&sort=asc"

Fetch a single event by id (note1... or nevent1... both work):

sh
curl "http://127.0.0.1:8080/api/v1/note1..."
curl "http://127.0.0.1:8080/api/v1/nevent1..."

Fetch an addressable event (naddr1...):

sh
curl "http://127.0.0.1:8080/api/v1/naddr1..."

Search:

sh
curl "http://127.0.0.1:8080/api/v1/npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkws3w8ktc/1?search=rust"

Tag filter:

sh
curl "http://127.0.0.1:8080/api/v1/npub180cvv07tjdrrgpa0j7j7tmnyl2yr6yr7l8j4s3evf6u64th6gkws3w8ktc/7?e=<event-id>&limit=100"