Skip to main content

LNURL Integration

AltZap implements the open LUD-06 and LUD-16 standards to bridge Lightning Network wallets with Nostr identity resolution. The protocol rules — chain advertisement and the callback — are in NIP-AZ; this page is how Zapf applies them.

LUD-16: Internet Identifiers​

LUD-16 allows Lightning wallets to resolve human-readable identifiers formatted like email addresses (e.g., user@example.com). Any compliant service can expose its identity graph to standard Lightning wallets through this mechanism. Because LNURL servers generate on-the-fly Lightning invoices for legacy accounts on behalf of users, standard wallets (like Phoenix or Wallet of Satoshi) can unknowingly pay a Discord user by resolving a Lightning Address.

Identifier Resolution​

The username portion of the LUD-16 address can be one of three things, resolved in priority order:

PriorityTypeExampleHow it resolves
1NIP-05 ↗ handlealice@example.comLooked up in the identity store by name
2ConnectionKey hasha1b2c3...@example.com (64-char hex)Looked up in the connection store by hash
3Raw pubkey<hex_pubkey>@example.com (64-char hex)Used directly as the recipient pubkey

For social Web Identity connections (Discord, GitHub, etc.), the identifier is the connectionKey hash — SHA256(platform_name:platform_id). Clients never expose the raw platform username in the LNURL path.

GET https://example.com/.well-known/lnurlp/<connectionKey>

The Callback Response​

The service resolves the identifier via the priority table above, then responds with a standard LNURL payload:

{
"callback": "https://example.com/lnurl/callback/<connectionKey>",
"maxSendable": 100000000,
"minSendable": 1000,
"metadata": "[[\"text/plain\",\"Zap <connectionKey>@example.com\"],[\"text/identifier\",\"<connectionKey>@example.com\"],[\"chain/flokicoin\",\"loki\"]]",
"tag": "payRequest",
"commentAllowed": 205,
"allowsNostr": true,
"nostrPubkey": "<recipient_or_server_pubkey>"
}

Nostr Extensions​

  • allowsNostr: true means, as in NIP-57 ↗, that the callback accepts a signed event in its nostr parameter. With at least one chain/<name> metadata entry, it means the endpoint accepts kind 9520 and kind 9523 AltZap Requests.
  • nostrPubkey is the key that signs the resulting kind 9521 receipt: the LNURL server's own key.

Invoice Generation (Callback)​

When the client accesses the callback URL (e.g., GET https://example.com/lnurl/callback/...&amount=10000&nostr=<url_encoded_kind_9520_or_9523>), the server executes the following logic:

  1. Validation: Check the request's signature first, then that its p is this address, its amount equals the amount parameter, and its chain is one this endpoint lists. The invoice's description hash is the SHA-256 of the request exactly as received.
  2. Target Resolution: Is the target a registered user with a connected NWC wallet?
    • Yes (Direct): The server acts as a passthrough, retrieving an invoice directly from the user's NWC node.
    • No (Custodial): The server generates an invoice from its own Master Node (the Fallback Lightning Address flow).
  3. Invoice Response: The server returns the generated pr (payment request) to the client.
{
"pr": "lnfc10n1...",
"routes": []
}

Multi-Chain Support​

The LUD-06/LUD-16 metadata (a JSON-encoded string of entries) is extended with chain tags to signal which Lightning Network chains and denominations the service accepts. This is a backward-compatible extension — existing Bitcoin-only wallets simply ignore unknown metadata entries and continue to function normally.

Chain Metadata Tags​

Chain support is declared via optional entries in the metadata JSON array using the format chain/<chain_name>:

TagDenominationDescription
chain/flokicoinlokiFlokicoin Lightning Network

If no chain entry is present, the endpoint settles on Bitcoin only and is a plain NIP-57 endpoint: clients send it a kind 9734 zap request, never an AltZap request. If at least one is present, only the listed chains are supported.

Example: Flokicoin Service​

A service operating on the Flokicoin Lightning Network includes the chain/flokicoin metadata tag with the loki denomination:

["chain/flokicoin", "loki"]

Amounts in minSendable and maxSendable are denominated in the smallest sub-unit of the declared chain, and the returned pr invoice conforms to the respective chain's Lightning invoice format.

ChainUnit NameExample
chain/flokicoinmilliloki (mloki)1000 = 1 loki
chain/bitcoinmillisatoshi (msats)1000 = 1 sat

Flokicoin Wallet Compatibility​

Standard Lightning wallets that do not understand chain/flokicoin will silently ignore the tag and attempt to pay the returned invoice. This will fail at the protocol level because the invoice belongs to a different chain — no funds are lost, no cross-chain confusion is possible. The wallet simply rejects the invoice as unpayable.

A service supporting several chains lists each; the request's chain tag says which one a zap settles on.