Skip to main content

Nostr Wallet Connect setup

Nostr Wallet Connect (NWC, NIP-47) connects Lightning Enable to a Lightning wallet you already run. Lightning Enable asks your wallet for an invoice, and asks it again later whether that invoice was paid. There is no payment provider account in between.

No account, no onboarding

This is the fastest lane to start receiving. If you have a wallet that speaks NWC, you can be minting L402 challenges in about a minute — no signup, no API key, no business verification anywhere.

Lightning Enable does not hold funds on this lane. Your wallet facilitates custody and settlement; Lightning Enable speaks NIP-47 to it and nothing else.

What you get, and what you don't

NWC is connected as a receive-only lane. Lightning Enable never instructs your wallet to send.

CapabilityNWCStrikeOpenNode
Create Lightning invoicesYesYesYes
Preimage for L402YesYesNo
Payment detectionPolling, up to 60sWebhookWebhook
On-chain addressesNoYesYes
Fiat-denominated invoicesNoYesNo
Refunds through the APINoYesYes

Two absences are worth reading twice:

  • No webhook. NIP-47 defines none. Lightning Enable detects payment by asking your wallet (lookup_invoice) once a minute, so an invoice can take up to 60 seconds to show as paid. Your own CallbackUrl webhook still fires, with the same payload shape the other providers send and "provider": "nwc".
  • No refunds. A refund is an outgoing payment, and this lane never sends. Refund a payer from your wallet app, or connect a Strike account if you need refunds issued through the API.

Choose a wallet

Lightning Enable speaks NIP-04 encryption to your wallet, which is the original NIP-47 default and the scheme most deployed wallets accept.

Known to work: CoinOS, Alby (NIP-04 connections), and other wallets that publish NIP-04 support in their NIP-47 capabilities.

A wallet that requires NIP-44 encryption is not supported on this lane. It shows up as an invoice request that times out after 30 seconds with a message naming the encryption mismatch, rather than as a silent failure.

Create the connection

  1. Open your wallet app and find its Nostr Wallet Connect (or "app connections") screen.
  2. Create a new connection for Lightning Enable.
  3. Grant it the make_invoice and lookup_invoice permissions. Lightning Enable calls nothing else, so do not grant pay_invoice — the connection cannot spend, and it should not be able to.
  4. Set a budget of zero if your wallet offers one. A receive-only connection needs no spending allowance.
  5. Copy the connection string. It looks like this:
nostr+walletconnect://<wallet-pubkey>?relay=wss://<relay-host>&secret=<secret>
Treat this string as a credential

The secret in that string authorises NIP-47 calls against your wallet. Store it the way you would store an API key. Lightning Enable encrypts it at rest with AES-256-GCM and never returns it from any endpoint — the settings API answers <set> and nothing more.

The fastest path: the MCP tool

If you're driving setup through the Lightning Enable MCP server (for example, via the producer-setup skill), one tool call replaces the two REST calls below:

l402_producer(action="configure_receive", nwcConnectionString="nostr+walletconnect://...")

This saves the connection string and switches your account onto the NWC lane in one step. Follow it with l402_producer(action="status") to confirm the lane is live before you mint anything against it — see Sell With Your Agent for the full flow.

Save it in Lightning Enable

Prefer to do it by hand? Save the string with your merchant API key:

curl -X PUT https://api.lightningenable.com/api/merchant/nwc-connection \
-H "X-API-Key: $LIGHTNING_ENABLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"nwcConnectionString": "nostr+walletconnect://<wallet-pubkey>?relay=wss://<relay-host>&secret=<secret>"
}'
{
"success": true,
"message": "Nostr Wallet Connect connection saved. Lightning Enable will create invoices on your wallet and poll it for payment — no webhook is needed.",
"nwcConnectionString": "<set>"
}

The connection string is validated before it is stored, so a malformed string comes back as a 400 instead of failing later on your first real payment.

Saving a connection string also puts your account on the NWC lane if you had not chosen a provider yet. To switch lanes explicitly:

curl -X PUT https://api.lightningenable.com/api/merchant/payment-provider \
-H "X-API-Key: $LIGHTNING_ENABLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"provider": "nwc"}'

Check it works

Mint a challenge. A successful mint proves the whole path: Lightning Enable reached your relay, your wallet decrypted the request, and it returned a real BOLT11 invoice.

curl -X POST https://api.lightningenable.com/api/l402/challenges \
-H "X-API-Key: $LIGHTNING_ENABLE_API_KEY" \
-H "Content-Type: application/json" \
-d '{"resource": "/hello", "priceSats": 10, "description": "NWC smoke test"}'

Pay the invoice from another wallet, then wait up to a minute. The invoice flips to paid, your CallbackUrl receives the webhook, and the preimage becomes available for L402 verification.

How amounts work

NWC settles in Bitcoin, and Lightning Enable performs no currency conversion on this lane. Request invoices in BTC (or SATS); a USD request returns a 400 naming the two options that work. L402 challenges are already priced in satoshis, so they need no change.

Invoices are for whole satoshis, with a minimum of 1.

Troubleshooting

"The wallet did not answer within 30s." The wallet app is offline, the connection was revoked in the wallet, or the wallet requires NIP-44 encryption. Check the connection is still listed in your wallet app, then re-copy and save the string.

"Could not reach any of the relays in the wallet's NWC connection string." The relay host in the string is down or unreachable. Some wallets let you regenerate a connection against a different relay; a string that advertises two relays fails over automatically.

"The wallet's reply could not be decrypted." The connection was rotated in the wallet app, so the secret Lightning Enable holds no longer matches. Create a fresh connection and save the new string.

A paid invoice still shows as unpaid. Detection on this lane polls once a minute, so allow 60 seconds. Beyond that, confirm the connection still has the lookup_invoice permission — a connection granted only make_invoice can create invoices it can never confirm.

See also

  • Sell With Your Agent — zero to a paid, agent-discoverable endpoint using this connection, driven end to end by an MCP agent
  • Strike account setup — the default lane, with webhooks, fiat invoices, and refunds
  • L402 Producer API — minting and verifying paid access once your wallet is connected