Bitswarm — Catalog & payment API (machine JSON)

Base URL (box): http://127.0.0.1:8765

Public tunnel: see /workspace/bitswarm/PUBLIC_URL.txt or data/PUBLIC_URL.txt

Legal: site catalog is SPDX-allowlisted only. Arbitrary magnets → 403.

Clients MAY seed user magnets locally; this hosted index WILL NOT.

All successful bodies are JSON. Errors often include "ok": false and "blocked": true.


Health

curl -sS "$BASE/api/health" | jq .

Example fields: ln_mode (nwc|sim), ln_address, user_pays, nwc_configured (boolean only — never a secret).


Catalog (allowlisted fixtures)

export BASE=http://127.0.0.1:8765
curl -sS "$BASE/api/catalog" | jq '{allowlist, count:(.items|length), items:[.items[]|{id,spdx,infohash,piece_count,has_real_torrent,sats_per_piece}]}'
FieldMeaning
items[].idFixture id
items[].spdxLicense (allowlisted)
items[].infohashProtocol content id
items[].piece_count / piece_sizePiece layout
items[].has_real_torrentBT magnet available
allowlistSPDX list enforced by site

CLI equivalent:

python thick-client/seed_cli.py catalog --api "$BASE"
python thick-client/seed_cli.py catalog --local

Reject arbitrary magnets (always)

curl -sS -X POST "$BASE/api/magnet" \
  -H 'Content-Type: application/json' \
  -d '{"magnet":"magnet:?xt=urn:btih:deadbeef"}' | jq .
# → HTTP 403, blocked:true

Same for /api/magnet/add and /api/torrent/add.


Register seeder (lud16 payee)

IH=$(curl -sS "$BASE/api/catalog" | jq -r '.items[]|select(.id=="tiny-lm-demo")|.infohash')
curl -sS -X POST "$BASE/api/seeder/register" \
  -H 'Content-Type: application/json' \
  -d "{\"infohash\":\"$IH\",\"sats_per_piece\":1,\"ln_receive\":\"erudite-jellyfish@lexe.app\"}" | jq '{ok,ad:{infohash:.ad.infohash,ln_receive:.ad.ln_receive,sats_per_piece:.ad.sats_per_piece}}'

Do not send magnet fields — rejected.


Piece invoice → pay → claim

# 1) Invoice (real LN floors to ≥21 sats)
INV=$(curl -sS -X POST "$BASE/api/piece/invoice" \
  -H 'Content-Type: application/json' \
  -d "{\"infohash\":\"$IH\",\"piece_index\":0}")
echo "$INV" | jq '{ok,invoice_id,amount_sats,lud16,memo,simulated,bolt11:(.bolt11[:24]+"…")}'

# 2) User pays bolt11 (WebLN / QR / NWC). Box does not auto-pay browser downloads.

# 3) Claim after settle (optional preimage)
IID=$(echo "$INV" | jq -r .invoice_id)
curl -sS -X POST "$BASE/api/piece/claim" \
  -H 'Content-Type: application/json' \
  -d "{\"invoice_id\":\"$IID\"}" | jq '{ok,verified,piece_index,size,pieces_held}'

Whole file:

curl -sS -X POST "$BASE/api/file/invoice" -H 'Content-Type: application/json' \
  -d "{\"infohash\":\"$IH\"}" | jq '{ok,invoice_id,amount_sats,remaining_count,lud16,memo}'
curl -sS -X POST "$BASE/api/file/claim" -H 'Content-Type: application/json' \
  -d "{\"invoice_id\":\"$IID\"}" | jq '{ok,pieces_held,filename}'

Invoice memo formats (protocol v0.2.0):

infohash|piece_index|piece_hash|nonce
infohash|ALL|remaining_count|file_hash|nonce

Stats / ToS pages

curl -sS "$BASE/api/stats" | jq '{ok, catalog:(.catalog|length), ln, legal}'
curl -sS -o /dev/null -w '%{http_code}\n' "$BASE/tos" "$BASE/stats"

Never logged

NWC URIs, seeds, preimages in server logs, or wallet secrets. Health/stats expose nwc_configured boolean only.