LaWalletdocs
SDK

NWC & Routing

Remote wallets, connection strings, and the four routing modes of a lightning address.

A lightning address on a LaWallet instance is a router: where an incoming payment ends up depends on the address's mode. The SDK exposes the full lifecycle — create NWC connections, inspect them, and bind them to addresses.

Address modes

ModePayments go…Requires
IDLENowhere yet — the address exists but can't receive
ALIASForwarded: LUD-16 resolution redirects to another addressredirect (user@host)
PROXY_ALIASThrough the instance's proxy, then on to a destinationOperator-configured proxy
CUSTOM_NWCStraight into the user's own wallet via Nostr Wallet ConnectA remoteWalletId they own

Pick ALIAS when the user already has a wallet address elsewhere and just wants the vanity name; pick CUSTOM_NWC for true self-custody — invoices are minted by their wallet, the instance only routes.

// Forward satoshi@your-domain to an existing wallet
await wallet.addresses.update('satoshi', {
  mode: 'ALIAS',
  redirect: 'satoshi@getalby.com'
})

// Or clear routing entirely
await wallet.addresses.update('satoshi', { mode: 'IDLE' })

Connecting a wallet (NWC)

A remote wallet wraps a Nostr Wallet Connect pairing. Create one from a nostr+walletconnect:// string, then bind it:

const remoteWallet = await wallet.remoteWallets.create({
  name: 'My Alby Hub',
  type: 'NWC',
  config: { connectionString: 'nostr+walletconnect://...' }
})

await wallet.addresses.update('satoshi', {
  mode: 'CUSTOM_NWC',
  remoteWalletId: remoteWallet.id
})

The connection string is stored encrypted server-side and never appears in list responses. The owner can read it back explicitly:

const secret = await wallet.remoteWallets.connectionString(remoteWallet.id)
const sats = await wallet.remoteWallets.balance(remoteWallet.id)

Revoking is soft — the wallet stops routing but its history survives:

await wallet.remoteWallets.remove(remoteWallet.id)

Server-minted wallets (LNCurl)

Instances with LNCurl enabled can mint a disposable custodial wallet on demand — useful to give brand-new users something that receives immediately, before they bring their own NWC:

const disposable = await wallet.remoteWallets.createLncurl({ isDefault: true })
// provider === 'lncurl'; upgrade the user to their own wallet later

Check settings.lncurl_enabled from the public instance settings before offering it.

In React

import { useAddress, useRemoteWallets } from '@lawallet/sdk/react'

function ConnectWallet({ username }: { username: string }) {
  const { update } = useAddress(username)
  const { create } = useRemoteWallets()

  const connect = async (connectionString: string) => {
    const remoteWallet = await create({
      name: 'My wallet',
      type: 'NWC',
      config: { connectionString }
    })
    await update({ mode: 'CUSTOM_NWC', remoteWalletId: remoteWallet.id })
  }

  return <NwcStringInput onSubmit={connect} />
}

Both hooks invalidate their caches after mutations, so every mounted list and detail view refreshes on its own — and the instance also broadcasts addresses:updated over SSE, which keeps other tabs in sync too.

Watching payments land

Once an address routes somewhere, received payments show up on useAddressInvoices(username) (or wallet.addresses.invoices(username)), live-refreshed by invoices:updated events. For payment flows you drive yourself, wallet.lud16.requestInvoice() + wallet.lud16.pollVerify() give you the public LUD-16/LUD-21 pair against any username on the instance.

On this page