Offers: add pull-based Payment Status Request (LUD-21-equivalent verify) - #17
Conversation
The Payment Receipt is push-based and ephemeral: published once at
settlement time, it is unrecoverable by any client not subscribed at
that exact moment. Merchant/point-of-sale software, LNURL-pay bridges,
and other request-scoped or stateless integrations therefore have no
reliable way to verify settlement, unlike LNURL's LUD-21 verify.
This adds a Payment Status Request: a kind 21001 query referencing the
original invoice request event id, answered with the existing receipt
payload on demand ("res":"ok" + preimage), "res":"pending" when unpaid,
or a new code 6 (Not Found) error. Services that do not support it
answer with the existing code 4 (Unsupported Feature).
No new payload semantics are introduced; only the ability to request
the status/receipt.
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01Q5zaCAS4EwuvG4cVitT3T5
|
Thanks for the write-up, interesting idea and I will ponder this a bit. First instinct is LNURL-Verify mainly exists because LNURL isn't bidirectional, it can only respond, not push. A nostr service handing out the invoices can push, so it's more of a workaround for the backend than the client. Is the idea that there's no service running at all and just static files, so callback is off the table? I'd think in that case you'd have to get the invoices client-side anyway, so I'm still a little confused how the follow-up is handled but not the sub. Couple things that come to mind from when we pushed the receipt: invoice GC (LND in our case) and extra weight on the server for tracking event ids. GC could make a paid invoice look like a miss if the follow-up lands after expiry / the receipt window. Will chew on it, mainly need to sketch how much has to go into Pub to make it reliable. |
Motivation
The Payment Receipt added to the Offers spec is exactly the right primitive —
{"res":"ok","preimage":...}is everything a verifier needs — but its delivery model is push-only: it is published once, at settlement time, as an ephemeral kind21001event. Any client not subscribed at that precise moment can never recover it.That excludes an important class of integrations: merchant and point-of-sale software, LNURL-pay bridges (e.g. bridgelet-style services wanting to offer LUD-21
verify), and other request-scoped or stateless clients — anything running on ordinary web hosting where no persistent Nostr subscription can be held open across the payment's lifetime. Today those integrations have no reliable way to confirm that an invoice they relayed was actually paid.We specifically encountered this when trying to add noffer support to our merchant software (https://github.com/BareBits/cashupayserver). On shared web hosting, we can't have long-running threads waiting for a kind 21001 event. Flakes due to restarted threads, brief network downtime, etc can prevent an invoice from showing as paid.
With this proposal, we can enable the following scenario:
Proposal
A Payment Status Request: a pull-based query answered with the existing receipt payload on demand.
21001to the receiving service, encrypted payload{"status_of": "<original_invoice_request_event_id>"}. Distinguished from an invoice request by the presence ofstatus_of/ absence ofoffer.{"res":"ok","preimage":...}, with a RECOMMENDEDbolt11echo so verifiers can bind the preimage to the payment hash statelessly;{"res":"ok"}, unchanged;{"res":"pending"};code: 6(Not Found).code: 4(Unsupported Feature).sha256(preimage)against the invoice payment hash.No new payload semantics are introduced — the only new capability is being able to ask for the status/receipt instead of having to catch it mid-air.
Open questions for maintainers
payment_hash? The event id is private-by-default; the payment hash would let anyone holding the invoice query status, which more closely matches LUD-21's semantics but widens who can obtain the preimage.code: 6the right number, or should Not Found reuse an existing code?bolt11echo should also be added to the push receipt for symmetry.