clone

nostr relays on demand at <name>.bind.ws: claim one with your key, pay in zaps past the free allowance

docs: the HTTP reference, every path the worker and a relay answer

Dami committed 2246325
commit
2246325219f9c3e29889e33893805e4747750087
parent
39b1150223b6748efe9b49d993766e9208c3902a
author
Dami <dami.etoile@gmail.com>
1 file changed, +111 -0
Adocs/14-http-reference.md111++++++++++++++++++++++++++++++
A docs/14-http-reference.md +111 -0
@@ -0,0 +1,111 @@
1+---2+title: HTTP reference3+audience: integrator4+---5+6+# HTTP reference7+8+Every path the worker and a relay answer. Paths are on `https://<name>.bind.ws` unless marked apex. Auth column: "NIP-98" is a signed request (see [Scripts and agents](13-scripts-and-agents.md)); "Blossom" is a kind 24242 token in the Authorization header; "none" is public. JSON errors carry `{ "error": "<prefix>: reason" }`; Blossom and NIP-96 errors also set an `X-Reason` header.9+10+Any request with `Accept: application/nostr+json` answers the NIP-11 document, whatever the path. A websocket upgrade on any path opens the relay. A blocked address is refused with 403 on the socket and on the doors that write, read or serve files; the page, NIP-11 and management stay open.11+12+## Apex13+14+| Path | Method | Auth | Answers | Status |15+|---|---|---|---|---|16+| `/` | GET | none | the landing page | 200 |17+| `/lease` | POST | NIP-98 optional | `{ name, url, console, expires_at, days, holder?, claim }`; a signature reserves the claim for that key | 201; 401 bad signature; 429 rate limited, five a minute per address, 60 overall; 503 no free name |18+| `/favicon.svg` | GET | none | the icon | 200 |19+20+## Relay page and information21+22+| Path | Method | Auth | Answers | Status |23+|---|---|---|---|---|24+| `/` | GET | none | the console, one page for visitors and owner alike | 200 |25+| `/` | GET with `Accept: application/nostr+json` | none | NIP-11: rules, limits, retention, `self`, `lease` while leased, `succession_pending` while warning | 200 |26+| `/` | POST, `content-type: application/nostr+json+rpc` | NIP-98 | NIP-86 management, `{ result }` or `{ error }` | 200; 400 invalid; 401 bad signature; 403 not allowed; 409 conflict |27+| `/people` | GET | none | `{ public, self, host, people }`, the members when the directory is public | 200 |28+| `/terms` | GET | none | the join terms as a page | 200; 404 none set |29+| `/signer.js` | GET | none | the NIP-46 client bundle, cached a week | 200 |30+| `/favicon.svg` | GET | none | the icon | 200 |31+| any | OPTIONS | none | CORS preflight | 200 |32+33+## Bridge34+35+Signed with NIP-98 over the exact URL, method and body. Same gates as a socket: the signer's bans, the read rule and the write rules apply, and the address is rate limited at four times the per-connection allowance.36+37+| Path | Method | Body | Answers | Status |38+|---|---|---|---|---|39+| `/events` | POST | one signed event | `{ event_id, accepted, message }` | 200 accepted; 400 refused, the message says why |40+| `/query` | POST | a non-empty list of filters | the events, newest first, up to the relay's query limit | 200; 400 bad filter; 403 read rule |41+| `/count` | POST | a non-empty list of filters | `{ count }` | 200; 400; 403 |42+43+## Files: Blossom44+45+| Path | Method | Auth | Answers | Status |46+|---|---|---|---|---|47+| `/upload` | HEAD | Blossom `upload` | whether an upload with the `X-SHA-256`, `X-Content-Type` and `X-Content-Length` headers would be accepted | 200; 400 bad headers; 401; 403 the write gate; 411 no length; 413 too big |48+| `/upload` | PUT | Blossom `upload` | the descriptor with `nip94` tags | 200 exists; 201 stored; 400; 401; 403 gate or a removed hash; 413 |49+| `/mirror` | PUT | Blossom `upload` | copies the blob at `{ "url": ... }` from another server, the descriptor | 200 exists; 201 stored; 400; 401; 403; 409 hash mismatch with the token; 413; 502 origin failed |50+| `/report` | PUT | none, the body is a signed kind 1984 | files a report for each `x` tag the relay holds | 200; 400 bad event or older than an hour; 403 unclaimed relay or banned reporter; 404 no such blob |51+| `/list/<pubkey>` | GET | none | that uploader's descriptors | 200; 400 bad pubkey |52+| `/<sha256>[.ext]` | GET, HEAD | none | the blob, ranges honoured | 200; 206; 404 |53+| `/<sha256>` | DELETE | Blossom `delete` | removes it; the uploader or the owner | 204; 400 token names another blob; 401; 403; 404 |54+55+## Files: NIP-9656+57+The same bucket and file list through the NIP-96 shape. Answers are `{ status, message, ... }` and errors set `X-Reason`.58+59+| Path | Method | Auth | Answers | Status |60+|---|---|---|---|---|61+| `/.well-known/nostr/nip96.json` | GET | none | `api_url`, `download_url`, `supported_nips`, content types, the free plan with the size cap | 200 |62+| `/nip96` | POST, multipart with a `file` field, optional `size` and `caption` | NIP-98, `payload` is the file's hash | the NIP-94 event in `nip94_event` and the Blossom URL | 200; 400; 401; 403; 413 |63+| `/nip96?page=&count=` | GET | NIP-98 | the caller's files | 200; 401 |64+| `/nip96/<sha256>` | GET, HEAD | none | the blob, same as the Blossom path | 200; 404 |65+| `/nip96/<sha256>` | DELETE | NIP-98 | removes it; the uploader or anyone with the storage action | 200; 401; 403; 404 |66+67+## Pages and feed68+69+Only while reads are open. Otherwise every path here answers 404, and an unclaimed relay answers 404 too. Cached five minutes.70+71+| Path | Method | Answers |72+|---|---|---|73+| `/e/<id>` | GET | a note as a page with Open Graph tags |74+| `/a/<d>` | GET | the owner's article with that identifier |75+| `/a/<npub or hex>/<d>` | GET | anyone's article |76+| `/feed.xml` | GET | Atom, the newest 50 notes and articles; `?kinds=1` or `?kinds=30023` to pick one, `?author=<hex>` for one person |77+78+## Card and QR79+80+| Path | Method | Answers | Status |81+|---|---|---|---|82+| `/card.json` | GET | `name`, `state`, `url`, `console`; on a claimed relay also `description`, `icon`, `owner`, `self`, `members` when the directory is public, `reads`, `writes`, `fuel`, `naddr`, `signed_url`, `image`; a lease adds `expires_at` | 200 |83+| `/card.nostr` | GET | the same facts as a kind 30078 signed by the relay's key | 200; 404 no owner |84+| `/card.svg` | GET | a 600 by 315 picture with the naddr as a QR | 200 |85+| `/qr.svg?text=` | GET | any text up to 512 bytes as a QR | 200; 400 empty; 413 too long |86+87+## People, invites and names88+89+| Path | Method | Auth | Answers | Status |90+|---|---|---|---|---|91+| `/.well-known/nostr.json?name=` | GET | none | NIP-05 for members with a name, with this relay as their relay | 200 |92+| `/invite/<code>` | GET | none | the invite page, with the join terms | 200 |93+| `/api/join-policy` | GET | none | `{ terms }` | 200 |94+| `/api/invites/claim` | POST `{ "code": ... }` | NIP-98 | `{ status: "joined" }` or `{ status: "already_member", role }` | 200; 400; 401; 403 invalid, used up or expired, or banned |95+96+## Dumps97+98+| Path | Method | Auth | Answers | Status |99+|---|---|---|---|---|100+| `/dumps/<name>.jsonl` | GET | NIP-98 with the storage action | the dump, one event per line | 200; 400 bad name; 401; 403; 404 |101+102+## Fuel103+104+| Path | Method | Auth | Answers | Status |105+|---|---|---|---|---|106+| `/fuel` | GET | none | meters, allowances, prices, balance and recent zaps | 200 |107+| `/fuel/invoice` | POST `{ "zapRequest": <kind 9734> }` | none | `{ invoice, providerPubkey, msats }` from the lightning provider | 200; 400 bad request or amount; 502 provider |108+109+## Websocket110+111+The relay itself: `wss://<name>.bind.ws`. NIP-01 with 09, 13, 40, 42, 45, 50, 62, 70 and 77, an `AUTH` challenge on connect, and `EOSE` hints per NIP-67. Kind 24133 passes the write and read rules so a NIP-46 signer can use the relay as transport.