Lighthouse Documentation

Self-hosted Nostr indexer for NIP-35 torrent events with federated curation

View the Project on GitHub gmonarque/lighthouse

API Reference

Complete documentation for Lighthouse REST and Torznab APIs.


Authentication

Most endpoints require an API key passed in the X-API-Key header:

curl -H "X-API-Key: your-api-key" http://localhost:9999/api/stats

The API key is configured in config.yaml or auto-generated on first run.


REST API

Base URL: http://localhost:9999/api

Dashboard

Get Statistics

GET /api/stats

Returns dashboard statistics.

Response:

{
  "total_torrents": 1234,
  "total_events": 5678,
  "trusted_publishers": 42,
  "categories": {
    "movies": 456,
    "tv": 234,
    "audio": 123
  }
}

Search Torrents

GET /api/search

Parameters:

Name Type Description
q string Search query
category integer Torznab category code
limit integer Max results (default: 50)
offset integer Pagination offset

Example:

curl "http://localhost:9999/api/search?q=ubuntu&category=4000"

Response:

{
  "results": [
    {
      "id": "abc123",
      "infohash": "aabbccdd...",
      "name": "Ubuntu 24.04 Desktop",
      "title": "Ubuntu 24.04 LTS",
      "size": 4500000000,
      "category": 4000,
      "seeders": 1500,
      "leechers": 50,
      "created_at": "2024-04-01T00:00:00Z",
      "magnet_uri": "magnet:?xt=urn:btih:..."
    }
  ],
  "total": 1
}

Torrents

Get Torrent Details

GET /api/torrents/{id}

Response:

{
  "id": "abc123",
  "infohash": "aabbccdd...",
  "infohash_version": "v1",
  "name": "Example Torrent",
  "title": "Example Title",
  "size": 1000000000,
  "category": 2000,
  "tags": ["linux", "distro"],
  "magnet_uri": "magnet:?xt=urn:btih:...",
  "curation_status": "accepted",
  "created_at": "2024-01-01T00:00:00Z",
  "event_id": "nostr_event_id",
  "pubkey": "publisher_npub"
}

Delete Torrent

DELETE /api/torrents/{id}

Removes a torrent from the local index.


Publishing

Parse Torrent File

POST /api/publish/parse-torrent
Content-Type: multipart/form-data

Upload a .torrent file to extract metadata.

Request:

curl -X POST \
  -F "file=@example.torrent" \
  http://localhost:9999/api/publish/parse-torrent

Response:

{
  "name": "Example File",
  "infohash": "aabbccdd...",
  "size": 1000000000,
  "files": [
    {"path": "file1.txt", "size": 500000000},
    {"path": "file2.txt", "size": 500000000}
  ]
}

Publish Torrent

POST /api/publish
Content-Type: application/json

Request Body:

{
  "name": "Example Torrent",
  "infohash": "aabbccdd...",
  "size": 1000000000,
  "category": 2000,
  "tags": ["linux"],
  "trackers": ["udp://tracker.example.com:6969"]
}

Response:

{
  "event_id": "nostr_event_id",
  "relays_published": ["wss://relay.damus.io"]
}

Trust Management

Get Whitelist

GET /api/trust/whitelist

Response:

{
  "entries": [
    {
      "npub": "npub1...",
      "note": "Trusted uploader",
      "added_at": "2024-01-01T00:00:00Z"
    }
  ]
}

Add to Whitelist

POST /api/trust/whitelist
Content-Type: application/json

Request Body:

{
  "npub": "npub1...",
  "note": "Trusted uploader"
}

Remove from Whitelist

DELETE /api/trust/whitelist/{npub}

Discover User Relays

Discovers a user’s preferred relays via NIP-65 and adds their write relays to your relay list.

POST /api/trust/whitelist/{npub}/discover-relays

Response:

{
  "npub": "npub1...",
  "relays_found": 5,
  "relays_added": 3,
  "message": "Discovered 5 relays, added 3 new relays"
}

Discover All Trusted Relays

Discovers relays for all whitelisted users.

POST /api/trust/whitelist/discover-all-relays

Response:

{
  "users_processed": 10,
  "total_relays_added": 8,
  "results": [
    {"npub": "npub1...", "relays_added": 3},
    {"npub": "npub2...", "relays_added": 0, "error": "No NIP-65 relay list"}
  ]
}

Get Blacklist

GET /api/trust/blacklist

Add to Blacklist

POST /api/trust/blacklist
Content-Type: application/json

Request Body:

{
  "npub": "npub1...",
  "reason": "Spam"
}

Remove from Blacklist

DELETE /api/trust/blacklist/{npub}

Curators (Federated Mode)

List Trusted Curators

GET /api/trust/curators

Response:

{
  "curators": [
    {
      "pubkey": "npub1...",
      "name": "Movie Curator",
      "weight": 1.0,
      "added_at": "2024-01-01T00:00:00Z"
    }
  ],
  "aggregation_policy": {
    "mode": "quorum",
    "quorum_required": 2
  }
}

Add Curator

POST /api/trust/curators
Content-Type: application/json

Request Body:

{
  "pubkey": "npub1...",
  "name": "Movie Curator",
  "weight": 1.0
}

Update Curator

PUT /api/trust/curators/{pubkey}
Content-Type: application/json

Request Body:

{
  "name": "Updated Name",
  "weight": 2.0
}

Remove Curator

DELETE /api/trust/curators/{pubkey}

Update Aggregation Policy

PUT /api/trust/aggregation
Content-Type: application/json

Request Body:

{
  "mode": "quorum",
  "quorum_required": 2
}

Modes: any, all, quorum, weighted


Decisions

List Decisions

GET /api/decisions

Parameters:

Name Type Description
status string accept or reject
curator string Curator pubkey
limit integer Max results
offset integer Pagination

Response:

{
  "decisions": [
    {
      "decision_id": "abc123",
      "decision": "accept",
      "reason_codes": [],
      "ruleset_type": "semantic",
      "ruleset_version": "1.0.0",
      "target_infohash": "aabbccdd...",
      "curator_pubkey": "npub1...",
      "created_at": "2024-01-01T00:00:00Z"
    }
  ],
  "total": 100
}

Get Decisions for Torrent

GET /api/decisions/{infohash}

Rulesets

List Rulesets

GET /api/rulesets

Response:

{
  "rulesets": [
    {
      "id": "abc123",
      "name": "Default Censoring",
      "type": "censoring",
      "version": "1.0.0",
      "hash": "sha256...",
      "rules_count": 10
    }
  ]
}

Get Ruleset

GET /api/rulesets/{id}

Import Ruleset

POST /api/rulesets
Content-Type: application/json

Request Body:

{
  "name": "Custom Rules",
  "type": "semantic",
  "version": "1.0.0",
  "rules": [
    {
      "id": "rule1",
      "name": "Minimum Size",
      "type": "threshold",
      "field": "size",
      "operator": "gte",
      "value": 1000000,
      "reason_code": "SEM_LOW_QUALITY"
    }
  ]
}

Reports

Submit Report

POST /api/reports
Content-Type: application/json

Request Body:

{
  "kind": "report",
  "category": "dmca",
  "target_infohash": "aabbccdd...",
  "evidence": "Description of issue",
  "jurisdiction": "US"
}

Categories: dmca, illegal, spam, malware, false_info, duplicate, other

List Reports

GET /api/reports

Parameters:

Name Type Description
status string pending, acknowledged, investigating, resolved, rejected
category string Filter by category

Get Pending Reports

GET /api/reports/pending

Update Report Status

PUT /api/reports/{id}
Content-Type: application/json

Request Body:

{
  "status": "resolved",
  "resolution": "Content removed"
}

Acknowledge Report

POST /api/reports/{id}/acknowledge

Comments

Get Comments for Torrent

GET /api/torrents/{infohash}/comments

Response:

{
  "comments": [
    {
      "id": "abc123",
      "content": "Great release!",
      "rating": 5,
      "author_pubkey": "npub1...",
      "created_at": "2024-01-01T00:00:00Z",
      "replies": []
    }
  ],
  "stats": {
    "total": 10,
    "average_rating": 4.5
  }
}

Add Comment

POST /api/torrents/{infohash}/comments
Content-Type: application/json

Request Body:

{
  "content": "Great release!",
  "rating": 5
}

Get Recent Comments

GET /api/comments/recent

Relays

List Relays

GET /api/relays

Response:

{
  "relays": [
    {
      "url": "wss://relay.damus.io",
      "name": "Damus",
      "preset": "public",
      "enabled": true,
      "connected": true,
      "last_event": "2024-01-01T00:00:00Z"
    }
  ]
}

Add Relay

POST /api/relays
Content-Type: application/json

Request Body:

{
  "url": "wss://relay.example.com",
  "name": "My Relay",
  "preset": "private"
}

Update Relay

PUT /api/relays/{url}
Content-Type: application/json

Request Body:

{
  "enabled": false
}

Delete Relay

DELETE /api/relays/{url}

Settings

Get Settings

GET /api/settings

Update Settings

PUT /api/settings
Content-Type: application/json

Request Body:

{
  "trust.depth": 1,
  "enrichment.tmdb_api_key": "your-key"
}

Get Identity

GET /api/settings/identity

Generate Identity

POST /api/settings/identity/generate

Import Identity

POST /api/settings/identity/import
Content-Type: application/json

Request Body:

{
  "nsec": "nsec1..."
}

Indexer Control

Get Indexer Status

GET /api/indexer/status

Response:

{
  "running": true,
  "events_processed": 12345,
  "last_event": "2024-01-01T00:00:00Z"
}

Start Indexer

POST /api/indexer/start

Stop Indexer

POST /api/indexer/stop

Resync Historical Events

Fetches historical torrent events from trusted uploaders. By default fetches all events (no time limit).

POST /api/indexer/resync

Parameters:

Name Type Description
days integer Limit to last N days (default: 0 = no limit)

Example:

# Fetch all historical events
curl -X POST http://localhost:9999/api/indexer/resync

# Fetch last 7 days only
curl -X POST "http://localhost:9999/api/indexer/resync?days=7"

Response:

{
  "status": "syncing",
  "message": "Fetching historical torrents",
  "days": 0
}

Torznab API

Torznab is a standardized API for torrent indexers, compatible with Prowlarr, Sonarr, Radarr, and other *arr applications.

Base URL: http://localhost:9999/api/torznab

Authentication

Pass API key as query parameter:

/api/torznab?apikey=your-api-key&t=search&q=query

Capabilities

GET /api/torznab?t=caps

Returns XML describing supported features and categories.

GET /api/torznab?t=search&q={query}

Parameters:

Name Type Description
q string Search query
cat string Category IDs (comma-separated)
limit integer Max results (default: 100)
offset integer Pagination offset
GET /api/torznab?t=tvsearch

Parameters:

Name Type Description
q string Search query
season string Season number
ep string Episode number
tvdbid string TVDB ID
imdbid string IMDB ID
GET /api/torznab?t=movie

Parameters:

Name Type Description
q string Search query
imdbid string IMDB ID
tmdbid string TMDB ID

Categories

ID Category
2000 Movies
2010 Movies/Foreign
2020 Movies/Other
2030 Movies/SD
2040 Movies/HD
2045 Movies/UHD
2050 Movies/BluRay
2060 Movies/3D
2070 Movies/DVD
2080 Movies/WEB-DL
5000 TV
5010 TV/WEB-DL
5020 TV/Foreign
5030 TV/SD
5040 TV/HD
5045 TV/UHD
5050 TV/Other
5060 TV/Sport
5070 TV/Anime
5080 TV/Documentary
3000 Audio
3010 Audio/MP3
3020 Audio/Video
3030 Audio/Audiobook
3040 Audio/Lossless
4000 PC
4010 PC/0day
4020 PC/ISO
4030 PC/Mac
4040 PC/Mobile-Other
4050 PC/Games
4060 PC/Mobile-iOS
4070 PC/Mobile-Android
7000 Books
7010 Books/Mags
7020 Books/EBook
7030 Books/Comics
7040 Books/Technical
7050 Books/Other
7060 Books/Foreign
6000 XXX

Error Responses

All endpoints return consistent error format:

{
  "error": "Error message",
  "code": "ERROR_CODE"
}

HTTP Status Codes

Code Description
200 Success
201 Created
400 Bad Request
401 Unauthorized (invalid/missing API key)
404 Not Found
500 Internal Server Error

Rate Limiting

Default limits:

Exceeded limits return 429 Too Many Requests.


Next Steps