Skip to content

Instantly share code, notes, and snippets.


Semisol/ Secret

Last active March 29, 2023 22:20
Show Gist options
  • Save Semisol/d913c93be3986122feaafaf8ffb6618c to your computer and use it in GitHub Desktop.
Save Semisol/d913c93be3986122feaafaf8ffb6618c to your computer and use it in GitHub Desktop.


Nostr Wallet Connect

draft optional author:kiwiidb author:bumi author:semisol author:vitorpamplona


Paying zaps should be possible without the user needing to open a different app to only pay a Lightning invoice. This NIP describes a way for users to control a remote Lightning node or a custodial Lightning wallet. When self-hosting, this setup does not require the user to run their own server, thereby bypassing certain hurdles that are commonly encountered when trying to connect to a Lightning node remotely.


  • client: Nostr app on any platform that wants to pay Lightning invoices
  • wallet service: Nostr app that typically runs on an always-on computer (eg. in the cloud or on a Raspberry Pi).


There are two event kinds:

  • NIP-47 request: 23194
  • NIP-47 response: 23195

Both the request and response events SHOULD only contain one p tag, containing the public key of the wallet service if this is a request, and the public key of the client if this is a response.

The content is encrypted with NIP04, and is a JSON object. The content depends on the kind.


    "cmd": "pay_invoice", // command, string
    "data": { // data, object
        "invoice": "lnbc50n1..." // command-related data


    "status": "ok", // status, "ok" | "error"
    "event": "0123456789abcdef...", // event the command is in response to, string
    "data": { // response data
        "preimage": "0123456789abcdef..." // command-related data

The data field SHOULD contain a message field with a human readable error message if the status is error.

Nostr Wallet Connect URI

client discovers wallet service by scanning a QR code, handling a deeplink or pasting in a URI.

The wallet service generates this connection URI with protocol nostr+walletconnect: and base path it's hex-encoded pubkey with the following query string parameters:

  • relay Required. URL of the relay where the wallet service is connected and will be listening for events. May be more than one.
  • secret Required. 32-byte randomly generated hex encoded string. The client should use this to sign events when communicating with the wallet service.
    • Authorization does not require passing keys back and forth.
    • The user can have different keys for different applications. Keys can be revoked and created at will and have arbitrary constraints (eg. budgets).
    • The key is harder to leak since it is not shown to the user and backed up.
    • It improves privacy because the user's main key would not be linked to their payments.

The client should then store this connection and use it when the user wants to perform actions like paying an invoice. Optionally it can display metadata about the connected wallet service from it's profile (name, image, url).

Example connection string




Description: Requests payment of an invoice.


    "invoice": "lnbc50n1..." // BOLT11 invoice, string


    "preimage": "0123456789abcdef..." // preimage after payment, string


Description: Requests the balance of the wallet.

Request: an empty JSON object.


    "balance": 100000 // balance in msat, int

Example pay invoice flow

  1. The user scans the QR code generated by the wallet service with their client application, they follow a nostrwalletconnect: deeplink or configure the connection details manually.
  2. client sends an event to with wallet service service with kind 23194. The content is a pay_invoice request. The private key is the secret from the connection string above.
  3. nostr-wallet-connect-service verifies that the author's key is authorized to perform the payment, decrypts the payload and sends the payment.
  4. nostr-wallet-connect-service responds to the event by sending an event with kind 23195 and content being a response either containing an error message or a preimage.

Using a dedicated relay

This NIP does not specify any requirements on the type of relays used. However, if the user is using a custodial service it might make sense to use a relay that is hosted by the custodial service. The relay may then enforce authentication to prevent metadata leaks. Not depending on a 3rd party relay would also improve reliability in this case.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment