Skip to content

Latest commit

 

History

History
237 lines (185 loc) · 17.8 KB

File metadata and controls

237 lines (185 loc) · 17.8 KB
title HTTP reference
audience integrator

HTTP reference

Every path the worker and a relay answer. Paths are on https://<name>.bind.ws unless marked apex. One read rule covers every door that shows events, files, names or presence: where the auth column says "the read rule", a relay whose reads are anyone answers without a signature, one whose reads are signed in takes any valid signature, and one whose reads are members takes a member's. Auth column: "NIP-98" is a signed request (see Scripts and agents); "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.

Requests with Accept: application/nostr+json answer the NIP-11 document, except explicit NIP-AD path discovery. A websocket upgrade on any relay 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.

Apex

Path Method Auth Answers Status
/ GET none the landing page 200
/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
/favicon.svg GET none the icon 200
/relay-config.schema.json GET none the JSON Schema of a relay configuration file, for $schema (Scripts and agents) 200
/connection-template.schema.json GET none the JSON Schema of a connection template, for $schema (Connection templates) 200
/.well-known/bindws/hostname?domain=<host> GET, on any host none whether the hostname is one of ours: the apex, a valid name under it, or a mapped custom hostname; no body. For a proxy issuing certificates on demand (Hosting without Cloudflare) 200 ours; 404 not

Relay page and information

Path Method Auth Answers Status
/ GET none the console, one page for visitors and owner alike 200
/ GET with Accept: application/nostr+json none NIP-11: rules, limits, retention, self, lease while leased, succession_pending while warning 200
/ 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; 429 active relay operation
/people GET none { public, self, host, people }, the members when the directory is public 200
/.well-known/nostr.json?path=<pathname> GET, HEAD; OPTIONS preflight the read rule for the group; public pages only NIP-AD path-keyed { filter, relays }, or {} without a mapping; NIP-AD web addresses 200; 400 invalid pathname; 401/403 group read rule; 405 other methods
/terms GET none the join terms as a page 200; 404 none set
/signer.js GET none the NIP-46 client bundle, cached a week 200
/favicon.svg GET none the icon 200
any OPTIONS none CORS preflight 200

A door that belongs to a feature the owner switched off (Relay configuration, Rules) answers 404: names, files (Blossom and NIP-96), pages and the feed. supported_nips drops the numbers of features that are off.

When GRASP is on and reads are open, NIP-11 also has a supported_grasps list containing GRASP-01 and validated GRASP-06 when enabled. GRASP-02/03/05 remain bounded previews pending interoperability and conformance review. The document also has a repo_acceptance_criteria string and, only for policy beyond ordinary spam controls, curation. See GRASP-01 Git hosting for the acceptance and Git protocol rules.

NIP-5A sites

Site hostnames are https://<npub>.<domain>, https://<pubkeyB36><dTag>.<domain> and https://v<snapshotIdB36>.<domain>. The label is resolved to the relay that holds the manifest, and the request reaches only the site door. Site hosting follows the sites feature and the relay's read rule.

Path Method Auth Answers Status
/ or a site path GET, HEAD the read rule the manifest's file; directory paths select index.html 200; 304 with a matching ETag; 401/403 by the read rule; 404 missing manifest, path or blob
/ or a site path other methods or websocket upgrade none method error 405
/.well-known/nsite/auth GET none, or NIP-98 when continuing an API session NIP-07 sign-in HTML with a five-minute challenge 401; 429 too many outstanding challenges
/.well-known/nsite/auth POST exact NIP-98 for this URL, method and body; body contains the signed kind 22242 challenge response sets the seven-day __Host-nsite cookie 204; 401 invalid or expired proof; 403 read rule; 413 body over 32 KiB
/.well-known/nostr.json?path=<pathname> GET, HEAD; OPTIONS preflight the site's read rule NIP-AD mapping to the live manifest with its hosting relay hint; no file fetch 200; 204 preflight; 400 invalid pathname; 401/403 read rule; 404 unavailable site; 405 other methods

Site responses include Content-Type, Content-Length when supplied by the source, an ETag equal to the file hash, X-Content-Type-Options: nosniff, and a cache policy based on the read rule. A missing path uses /404.html when the manifest contains it; a missing manifest, unavailable file, or failed hash check returns a plain 404. On a local cache miss the door may proxy the file from up to ten manifest servers followed by up to ten author kind 10063 servers, subject to a cap of min(maxBlobMB, 32 MiB). Only public HTTPS URLs and checked redirects are used, and caller credentials are not forwarded.

The sign-in cookie is Secure, HttpOnly and SameSite=Lax. The site door checks it against the current read rule on every request. A caller can use exact NIP-98 directly instead of a cookie.

GRASP-01 Git

When the feature is on, reads are open and the repository announcement is accepted, the percent-encoded repository path exposes Git Smart HTTP. It uses public HTTP with signed NIP-34 state authorizing writes. A restricted read rule disables this door rather than offering authenticated private Git.

Path Method Auth Answers Status
/<npub>/<identifier>.git GET, HEAD public repository page 200; 404 unhosted repository
/<npub>/<identifier>.git/info/refs?service=git-upload-pack or service=git-receive-pack GET public service and ref advertisement 200; 400 unsupported service
/<npub>/<identifier>.git/git-receive-pack POST signed NIP-34 state and PR rules receive-pack report 200, including protocol-level rejection; 409 rejection without report-status; 400 malformed request; 413 request limit; 415 media type
/<npub>/<identifier>.git/git-upload-pack POST public bounded pack for reachable, tip or filtered wants 200; 400 malformed or invalid want; 413 request or response limit; 415 media type
a Git path OPTIONS none CORS preflight 204

The door also returns 403 for a restricted read rule, inactive relay or exhausted fuel; 429 for rate limits or an operation already in progress; and 503 when repository storage is unavailable. Receive-pack clients must read the Git report: HTTP 200 alone does not mean a push was accepted.

Git responses include Access-Control-Allow-Origin: *, Access-Control-Allow-Methods: GET, POST and Access-Control-Allow-Headers: Content-Type, Authorization, Git-Protocol, X-Git-Request-Id. Upload-pack advertises allow-reachable-sha1-in-want, allow-tip-sha1-in-want and filter, and accepts blob:none and tree:0. An unknown refs/nostr/<event-id> has a 20-minute holding window. Expired unmatched refs are hidden and scheduled for deletion, but immutable Git objects remain in retained storage. Expiring a ref does not make those bytes free.

The owner can inspect one accepted repository through the NIP-86 gitstorage method at the relay root. It performs a bounded, read-only walk of SQLite metadata and reports the backend, object count, raw bytes, compressed bytes, metadata bytes, ref count, receipt count and the relay's complete physicalDatabaseBytes. The physical database total includes all relay data, indexes and Git data, so the diagnostic object bytes are not billed again. The method reports zero R2 gets and lists for this backend. Its SQL metadata reads contribute to the ordinary row meter. It changes no stored objects, refs or receipts and has a 60-second per-instance cooldown; a Durable Object restart or eviction resets that cooldown.

Method Parameters Auth Answers Status
gitstorage repository owner hex pubkey, identifier NIP-98, owner with the storage action bounded SQLite object, ref and receipt inventory, physical database size and limits 200; 400 invalid parameters; 403 inactive, fuel or role; 404 feature or repository unavailable; 429 cooldown or another repository operation

The owner-only storagestats method also includes result.graspSync when GRASP synchronization is configured. It reports enabled, partial, event counts (jobs, failed, history, due) and Git counts (jobs, failed, due). due is the earliest Unix timestamp or null; failed counts rows with durable error details, and history counts unfinished history windows.

Custom domains

These NIP-86 methods are owner-only and use the relay's normal NIP-98 RPC endpoint. The optional site label uses the same root, named-site and snapshot grammar as the hostname forms above. An omitted or empty label targets the relay itself. listdomains includes the current site field.

Method Parameters Answers Status
adddomain host, optional site label creates the custom hostname and maps it to the relay or selected site 200; 400 invalid or duplicate; 403; 502 Cloudflare failure
setdomainsite host, optional site label changes an existing hostname's destination 200; 400 invalid host or site; 403
listdomains none custom host records, including site when selected 200; 403

Bridge

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.

Path Method Body Answers Status
/events POST one signed event { event_id, accepted, message } 200 accepted; 400 refused, the message says why
/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
/count POST a non-empty list of filters { count } 200; 400; 403

Files: Blossom

Path Method Auth Answers Status
/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
/upload PUT Blossom upload the descriptor with nip94 tags 200 exists; 201 stored; 400; 401; 403 gate or a removed hash; 413
/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
/report PUT none, the body is a signed kind 1984; the reporter must pass the read rule files a report for each x tag the relay holds 200; 400 bad event or older than an hour; 401 reporter must sign in under a read rule; 403 unclaimed relay, banned reporter or reporter not admitted by the read rule; 404 no such blob
/list/<pubkey> GET the read rule: none while reads are open, else Blossom list or NIP-98 that uploader's descriptors 200; 400 bad pubkey; 401; 403
/<sha256>[.ext] GET, HEAD the read rule: none while reads are open, else Blossom get or NIP-98 the blob, ranges honoured; not cacheable by shared caches when gated 200; 206; 401; 403; 404
/<sha256> DELETE Blossom delete removes it; the uploader or the owner 204; 400 token names another blob; 401; 403; 404

Files: NIP-96

The same bucket and file list through the NIP-96 shape. Answers are { status, message, ... } and errors set X-Reason.

Path Method Auth Answers Status
/.well-known/nostr/nip96.json GET none api_url, download_url, supported_nips, content types, the free plan with the size cap 200
/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
/nip96?page=&count= GET NIP-98 the caller's files 200; 401
/nip96/<sha256> GET, HEAD the read rule, as the Blossom path the blob, same as the Blossom path 200; 401; 403; 404
/nip96/<sha256> DELETE NIP-98 removes it; the uploader or anyone with the storage action 200; 401; 403; 404

Pages and feed

Only while reads are open. Otherwise every path here answers 404, and an unclaimed relay answers 404 too. Cached five minutes.

Path Method Answers
/e/<id> GET a note as a page with Open Graph tags
/a/<d> GET the owner's article with that identifier
/a/<npub or hex>/<d> GET anyone's article
/feed.xml GET Atom, the newest 50 notes and articles; ?kinds=1 or ?kinds=30023 to pick one, ?author=<hex> for one person

Card and QR

Path Method Answers Status
/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, nprofile (the owner with this relay as the hint), signed_url, image; a lease adds expires_at 200
/card.nostr GET the same facts as a kind 30078 signed by the relay's key 200; 404 no owner
/card.svg GET a 600 by 315 picture with the naddr as a QR 200
/qr.svg?text= GET any text up to 512 bytes as a QR 200; 400 empty; 413 too long

Connect

Path Method Auth Answers Status
/connect.json GET NIP-98 optional { relay: { url, host, web, name }, viewer, connections }: the Connect fold's shortcuts the asker may see, links filled in for them, each { template, title, about, app, where, icon, visibility, links, qr, needsUser }. Unsigned, the public ones, with the links that need a viewer left out and needsUser set, cached a minute; signed, that key's view, no-store (Connection templates) 200; 401 bad signature

People, invites and names

The NIP-86 createclaim, listclaims and deleteclaim methods use POST / to manage the same codes redeemed below. Their parameters, results and limits are in NIP-86 membership claims; the bind.ws claim method still concerns relay ownership.

Path Method Auth Answers Status
/.well-known/nostr.json?name= GET none for a name; the directory switch for the listing without one, else NIP-98 by a member NIP-05 for the member with that name, with this relay as their relay; without a name, every named member when the directory is public 200; 401 bad signature
/invite/<code> GET none the invite page, with the join terms 200
/api/join-policy GET none { terms } 200
/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

Dumps

Path Method Auth Answers Status
/dumps/<name>.jsonl GET NIP-98 with the storage action the dump, one event per line 200; 400 bad name; 401; 403; 404

Fuel

Path Method Auth Answers Status
/fuel GET none meters, allowances, prices and balance; who zapped is in the stats management method 200
/fuel/invoice POST { "zapRequest": <kind 9734> } none { invoice, providerPubkey, msats } from the lightning provider 200; 400 bad request or amount; 502 provider

Views

Path Method Auth Answers Codes
/view/<name> GET none for a public view; NIP-98 by a member for a members-only one; zaps, moderation, calendar, articles and presence follow the read rule, profiles and relays the directory switch the view's latest signed kind 30078 record as JSON, or presence as a kind 20078 from memory 200; 401 auth-required: when a members-only view is asked for without a signature; 403 when the signer is not a member; 404 when the view is off, unknown, or has not run yet

Names: profiles, relays, calendar, moderation, articles, zaps, presence. The information document lists the ones a relay keeps under views, with each one's kind, d, trigger and audience.

Websocket

The relay itself: wss://<name>.bind.ws. NIP-01 with 09, 13, 17 and 59 as private kinds, 29 and 43 for the group, 40, 42, 45, 50, 56, 62, 66 as a kind 30166 record signed by the relay about itself, 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 or client can use the relay as transport: it is delivered to a socket that has proved a party's key with AUTH, or to a subscription that names one in #p or authors, and never to a bare subscription to the kind.