Nostr WoT
Backend API

WoT Oracle

Query directed follow distance and public mute evidence over HTTP. Version 0.3.0, with no extension required.

What It Does

The Oracle indexes kind-3 follows and public pubkey entries from kind-10000 mute lists received through configured relays. Coverage is limited to those indexed events. Follow distance and mute evidence remain separate; the API does not combine them into a trust score.

Example: If Alice follows Bob, and Bob follows Carol, then the distance from Alice to Carol is 2 hops.

Release capabilities

0.3.0Release
1–5Maximum search depth (hops)
100Targets per batch
3 / 10000Indexed event kinds

API Endpoints

Illustrative responses using synthetic 64-character hexadecimal pubkeys. Actual results depend on indexed events. See the API reference for all endpoints, including /mutes, /trust and /ready.

GET /distance

Query the social distance between two pubkeys.

http
GET /distance?from=aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&to=bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb&max_hops=3
json
{
  "from": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "to": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
  "hops": 2,
  "path_count": 1,
  "mutual_follow": false
}

POST /distance/batch

Query distances from one pubkey to multiple targets.

http
POST /distance/batch
Content-Type: application/json

{
  "from": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "targets": [
    "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"
  ],
  "max_hops": 3
}
json
{
  "from": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "results": [
    {
      "from": "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
      "to": "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb",
      "hops": 2,
      "path_count": 1,
      "mutual_follow": false
    }
  ]
}

GET /stats

Get statistics about the indexed graph.

http
GET /stats
json
{
  "node_count": 3,
  "edge_count": 2,
  "nodes_with_follows": 2,
  "mute_edge_count": 0,
  "nodes_with_mute_lists": 1,
  "sync": {
    "running": true,
    "ready": false,
    "last_event_received_at": 0,
    "last_persisted_at": 0,
    "persisted_events": 0,
    "lagged_notifications": 0,
    "persistence_errors": 0,
    "coverage": "configured_relays_only"
  },
  "cache": {
    "size": 0,
    "capacity": 10000,
    "ttl_secs": 300
  },
  "locks": {
    "write_lock_count": 0,
    "write_lock_avg_us": 0,
    "write_lock_max_us": 0,
    "read_lock_count": 0,
    "read_lock_avg_us": 0,
    "read_lock_max_us": 0
  }
}

GET /health

Process liveness and release version. Use /ready to check ingestion readiness.

http
GET /health
json
{
  "status": "healthy",
  "version": "0.3.0"
}

Self-Hosting

Examples use v0.3.0. Docker and Compose publish on localhost:8080. Public deployments need a reverse proxy that replaces client-IP headers. Native builds need Rust 1.93, pkg-config and OpenSSL development libraries.

Docker (Recommended)

terminal
$docker pull ghcr.io/nostr-wot/nostr-wot-oracle:0.3.0
$
$docker run -d --name nostr-wot-oracle \
$ -p 127.0.0.1:8080:8080 \
$ -v wot-data:/app/data \
$ ghcr.io/nostr-wot/nostr-wot-oracle:0.3.0

Docker Compose

terminal
$git clone --branch v0.3.0 --depth 1 https://github.com/nostr-wot/nostr-wot-oracle.git
$cd nostr-wot-oracle
$docker compose up -d

From source (Rust 1.93)

terminal
$git clone --branch v0.3.0 --depth 1 https://github.com/nostr-wot/nostr-wot-oracle.git
$cd nostr-wot-oracle
$rustup toolchain install 1.93.0
$cargo +1.93.0 build --locked --release
$./target/release/wot-oracle

Configuration

Environment variables below show native binary defaults. The Docker image uses /app/data/wot.db; Compose publishes to loopback by default. Cache size is bounded to 100–100000, TTL to 10–3600 seconds, and the rate limit to 1–1000 requests/minute.

VariableDefaultDescription
RELAYSwss://relay.damus.io,wss://nos.lol,wss://relay.primal.net/,wss://relay.mostr.pub/Comma-separated relay URLs
HTTP_PORT8080Server port
DB_PATHwot.dbSQLite database location
RATE_LIMIT_PER_MINUTE100Query throttle per IP
CACHE_SIZE10000Maximum entries in the Moka query cache
CACHE_TTL_SECS300Cache expiration (5 min)

Architecture

Graph Storage

In-memory graph for fast traversal, backed by SQLite for persistence. Syncs continuously from configured Nostr relays.

Pathfinding

Bidirectional breadth-first search computes shortest directed follow paths. Runtime depends on graph size, branching and search depth.

Caching

Moka query cache with configurable capacity and TTL. Entries are invalidated when the graph revision changes. Latency depends on the deployment and workload.

Rate Limiting

Per-IP rate limiting protects the service from abuse. Configurable limits for different deployment scenarios.

Public Instance

A public instance is available for development and testing:

https://wot-oracle.mappingbitcoin.com

Limits depend on deployment settings. Handle HTTP 429 with backoff. Graph-query saturation returns 503; /health and /ready remain available outside the data-endpoint limiter.

Open Source

Written in Rust. MIT licensed. Self-host for your community or contribute improvements.