brain-aiolabs/inbox/2026-10-09_nostr-request-response-and-delivery-guarantees.md
2026-10-09 21:34:39 +02:00

2.2 KiB

date tags hubs urls
2026-10-09
question
nostr
protocols
https://github.com/nostr-protocol/nips/blob/master/01.md
https://github.com/nostr-protocol/nips/blob/master/46.md
https://github.com/nostr-protocol/nips/blob/master/47.md
https://github.com/nostr-protocol/nips/blob/master/90.md

Nostr request/response and delivery guarantees

Open question: how does Nostr handle request/response when a machine needs to know its message was received? Nostr is publish/subscribe with no end-to-end delivery receipt, so every "RPC over Nostr" NIP builds its own correlation on top.

What exists today (to verify and expand):

  • Relay-level ack only. NIP-01 ["OK", <event-id>, true|false, <msg>] tells the publisher the relay stored the event. Says nothing about the recipient. Publishing to several relays gives several OKs.
  • Correlation by e tag. Every request/response NIP has the responder publish a new event that tags the request's id; the requester subscribes with a #e filter (and usually #p on its own pubkey) and waits with a timeout. No response within the timeout = treat as not delivered, retry with the same request id (responders should be idempotent on it).
  • NIP-46 (remote signing, nsecbunkerd): kind 24133, encrypted JSON-RPC {id, method, params} → {id, result, error}. The id in the payload is the correlation key, the event e/p tags are routing.
  • NIP-47 (Nostr Wallet Connect): kind 23194 request → 23195 response, same pattern, plus 23196 notifications. Also expiration tag so a stale request is dropped rather than executed late.
  • NIP-90 (DVMs): kinds 5xxx request, 6xxx result, 7000 job feedback with status (payment-required, processing, error, success). This is the closest thing to a progress/ack channel in the protocol.
  • NIP-17 DMs: no read receipts by design.

Our own use: lnbits ↔ nsecbunkerd over NIP-46, and anything the bots do over Nostr. The practical answer is: own correlation id, subscribe before publishing, bounded timeout, idempotent retry, and treat relay OK as "sent" not "received". Worth a reference note once the pattern is written down with code pointers (nsecbunkerd client, nostrclient).