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}]}'
| Field | Meaning |
|---|---|
items[].id | Fixture id |
items[].spdx | License (allowlisted) |
items[].infohash | Protocol content id |
items[].piece_count / piece_size | Piece layout |
items[].has_real_torrent | BT magnet available |
allowlist | SPDX 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.