Skip to main content

Nostr Wallet Connect (NWC)

Nostr Wallet Connect (NWC) is an open protocol that enables Nostr apps to interact with Lightning wallets. Defined by NIP-47, it's the standard for wallet connectivity in the Nostr ecosystem.

What is NWC?

NWC provides:

  • Standardized communication between apps and wallets
  • Encrypted messages via Nostr relays
  • Budget controls for spending limits
  • Cross-platform compatibility

How NWC Works

Connection Flow

  1. Wallet generates connection string
  2. User imports into app
  3. App sends encrypted requests
  4. Wallet processes and responds

Communication

All messages are NIP-04 encrypted Nostr events:

The relay only sees encrypted blobs - it can't read payment details.

Connection String Format

nostr+walletconnect://[wallet_pubkey]?
relay=[relay_url]&
secret=[shared_secret]&
lud16=[optional_lightning_address]

Components

ComponentPurpose
wallet_pubkeyWallet's Nostr public key
relayRelay for communication
secretEncryption key (hex)
lud16Optional Lightning address

Example

nostr+walletconnect://b889ff5b1513b641e2a139f661a661364979c5beee91842f8f0ef42ab558e9d4?
relay=wss%3A%2F%2Frelay.getalby.com%2Fv1&
secret=71a8c14c1407c113601079c4302dab36460f0ccd0ad506f1f2dc73b5100e4f3c

NWC Commands

pay_invoice

Pay a Lightning invoice:

{
"method": "pay_invoice",
"params": {
"invoice": "lnbc1000n1..."
}
}

Response:

{
"result_type": "pay_invoice",
"result": {
"preimage": "payment_preimage_hex"
}
}

make_invoice

Create an invoice:

{
"method": "make_invoice",
"params": {
"amount": 1000,
"description": "Payment for service",
"expiry": 3600
}
}

Response:

{
"result_type": "make_invoice",
"result": {
"invoice": "lnbc1000n1...",
"payment_hash": "..."
}
}

get_balance

Check wallet balance:

{
"method": "get_balance",
"params": {}
}

Response:

{
"result_type": "get_balance",
"result": {
"balance": 50000
}
}

get_info

Get wallet information:

{
"method": "get_info",
"params": {}
}

Response:

{
"result_type": "get_info",
"result": {
"alias": "My Wallet",
"color": "#ff9900",
"pubkey": "node_pubkey",
"network": "mainnet",
"methods": ["pay_invoice", "make_invoice", "get_balance"]
}
}

lookup_invoice

Check invoice status:

{
"method": "lookup_invoice",
"params": {
"payment_hash": "..."
}
}

list_transactions

Get transaction history:

{
"method": "list_transactions",
"params": {
"limit": 10,
"offset": 0
}
}

Event Kinds

KindPurpose
23194NWC Request (app → wallet)
23195NWC Response (wallet → app)
13194NWC Info event

Setting Up NWC

Wallet Side (Service)

  1. Generate keypair for NWC connections
  2. Set up relay for communication
  3. Generate connection strings for users
  4. Process incoming requests
  5. Send encrypted responses

App Side (Client)

  1. Parse connection string
  2. Store wallet pubkey and secret
  3. Subscribe to response events
  4. Send encrypted requests
  5. Handle responses

Example: Connecting Alby to Damus

  1. In Alby:

    • Go to Settings → Connections
    • Create new app connection
    • Copy NWC connection string
  2. In Damus:

    • Go to Settings → Wallet
    • Select "Nostr Wallet Connect"
    • Paste connection string
    • Test with small zap

Budget Controls

Wallets can implement spending limits:

const connection = {
budgetMsat: 100000000, // 100,000 sats
budgetRenewal: "monthly",
singlePaymentLimit: 10000000 // 10,000 sats max per payment
};
Security Practice

Always set a reasonable budget when creating NWC connections. This limits damage if the connection is compromised.

Error Handling

Error Response Format

{
"result_type": "pay_invoice",
"error": {
"code": "INSUFFICIENT_BALANCE",
"message": "Not enough funds"
}
}

Common Error Codes

CodeMeaning
RATE_LIMITEDToo many requests
NOT_IMPLEMENTEDMethod not supported
INSUFFICIENT_BALANCENot enough funds
PAYMENT_FAILEDLightning payment failed
NOT_FOUNDInvoice not found
QUOTA_EXCEEDEDBudget limit reached
RESTRICTEDPermission denied
UNAUTHORIZEDInvalid connection
INTERNALServer error

Implementations

Wallet Services

  • Alby - Full NWC support
  • Alby Hub - Self-hosted NWC
  • Mutiny - NWC enabled
  • LNbits - NWC extension
  • Zeus - Mobile NWC

Libraries

  • @getalby/sdk - JavaScript SDK
  • nwc - Rust library
  • nostr-tools - TypeScript utilities
  • NDK - Nostr Development Kit

Example Code

import { webln } from '@getalby/sdk';

// Connect via NWC
const nwc = new webln.NWC({
nostrWalletConnectUrl: 'nostr+walletconnect://...'
});

await nwc.enable();

// Pay invoice
const result = await nwc.sendPayment('lnbc1000n1...');
console.log('Payment preimage:', result.preimage);

// Get balance
const balance = await nwc.getBalance();
console.log('Balance:', balance.balance, 'sats');

Security Considerations

Connection String Safety

  • Treat like a password
  • Don't share publicly
  • Regenerate if compromised
  • Use separate connections per app

Relay Trust

The relay can see:

  • That communication is happening
  • Event kinds and pubkeys
  • Cannot read encrypted content

Revocation

To revoke access:

  1. Delete the connection in wallet
  2. Wallet stops responding to requests
  3. App can no longer make payments

Resources


Universal Protocol

NWC eliminates the need for apps to integrate with each wallet individually. One protocol connects any app to any compatible wallet.