NIP-47 Add Hold Invoice Support (#1913)

Co-authored-by: Fmar <frnandu@gmail.com>
Co-authored-by: Roland <33993199+rolznz@users.noreply.github.com>
This commit is contained in:
frnandu
2026-02-03 19:41:08 +01:00
committed by GitHub
parent 90a60bd210
commit 01838f302d

121
47.md
View File

@@ -371,7 +371,7 @@ Response:
"result_type": "lookup_invoice", "result_type": "lookup_invoice",
"result": { "result": {
"type": "incoming", // "incoming" for invoices, "outgoing" for payments "type": "incoming", // "incoming" for invoices, "outgoing" for payments
"state": "pending", // can be "pending", "settled", "expired" (for invoices) or "failed" (for payments), optional "state": "pending", // can be "pending", "settled", "accepted" (for hold invoices), "expired" (for invoices) or "failed" (for payments), optional
"invoice": "string", // encoded invoice, optional "invoice": "string", // encoded invoice, optional
"description": "string", // invoice's description, optional "description": "string", // invoice's description, optional
"description_hash": "string", // invoice's description hash, optional "description_hash": "string", // invoice's description hash, optional
@@ -420,7 +420,7 @@ Response:
"transactions": [ "transactions": [
{ {
"type": "incoming", // "incoming" for invoices, "outgoing" for payments "type": "incoming", // "incoming" for invoices, "outgoing" for payments
"state": "pending", // can be "pending", "settled", "expired" (for invoices) or "failed" (for payments), optional "state": "pending", // can be "pending", "settled", "accepted" (for hold invoices), "expired" (for invoices) or "failed" (for payments), optional
"invoice": "string", // encoded invoice, optional "invoice": "string", // encoded invoice, optional
"description": "string", // invoice's description, optional "description": "string", // invoice's description, optional
"description_hash": "string", // invoice's description hash, optional "description_hash": "string", // invoice's description hash, optional
@@ -485,6 +485,89 @@ Response:
} }
``` ```
### `make_hold_invoice`
Creates a hold invoice using a pre-generated preimage.
Request:
```jsonc
{
"method": "make_hold_invoice",
"params": {
"amount": 123, // value in msats
"description": "string", // invoice's description, optional
"description_hash": "string", // invoice's description hash, optional
"expiry": 213 // expiry in seconds from time invoice is created for a payment to be initiated, optional. This does not determine how long a payment can be held (see `settle_deadline`)
"payment_hash": "string" // Payment hash for the payment generated from the preimage
"min_cltv_expiry_delta": 144 // The minimum CLTV delta to use for the final hop, optional
}
}
```
Response:
```jsonc
{
"result_type": "make_hold_invoice",
"result": {
"type": "incoming", // "incoming" for invoices, "outgoing" for payments
"invoice": "string", // encoded invoice, optional
"description": "string", // invoice's description, optional
"description_hash": "string", // invoice's description hash, optional
"payment_hash": "string", // Payment hash for the payment
"amount": 123, // value in msats
"created_at": unixtimestamp, // invoice/payment creation time
"expires_at": unixtimestamp, // invoice expiration time, optional if not applicable
"metadata": {} // generic metadata that can be used to add things like zap/boostagram details for a payer name/comment/etc.
}
}
```
### `cancel_hold_invoice`
Cancels a hold invoice using the payment hash
Request:
```jsonc
{
"method": "cancel_hold_invoice",
"params": {
"payment_hash": "string" // Payment hash for the payment generated from the preimage
}
}
```
Response:
```jsonc
{
"result_type": "cancel_hold_invoice",
"result": {}
}
```
### `settle_hold_invoice`
Settles a hold invoice using the preimage
Request:
```jsonc
{
"method": "settle_hold_invoice",
"params": {
"preimage": "string" // preimage for the payment
}
}
```
Response:
```jsonc
{
"result_type": "settle_hold_invoice",
"result": {}
}
```
## Notifications ## Notifications
### `payment_received` ### `payment_received`
@@ -539,6 +622,30 @@ Notification:
} }
``` ```
### `hold_invoice_accepted`
Description: Sent when a payer accepts (locks in) a hold invoice. To avoid locking up funds in channels the hold invoice SHOULD be settled or canceled within a few minutes of receiving this event.
Notification:
```jsonc
{
"notification_type": "hold_invoice_accepted",
"notification": {
"type": "incoming",
"state": "accepted", // optional
"invoice": "string", // encoded invoice
"description": "string", // invoice's description, optional
"description_hash": "string", // invoice's description hash, optional
"payment_hash": "string", // Payment hash for the payment
"amount": 123, // value in msats
"created_at": unixtimestamp, // invoice/payment creation time
"expires_at": unixtimestamp, // invoice expiration time
"settle_deadline": blocknumber, // invoice can only be safely settled or canceled before this block number.
"metadata": {} // generic metadata that can be used to add things like zap/boostagram details for a payer name/comment/etc.
}
}
```
## Example pay invoice flow ## Example pay invoice flow
0. The user scans the QR code generated by the **wallet service** with their **client** application, they follow a `nostr+walletconnect://` deeplink or configure the connection details manually. 0. The user scans the QR code generated by the **wallet service** with their **client** application, they follow a `nostr+walletconnect://` deeplink or configure the connection details manually.
@@ -668,6 +775,16 @@ Here are some properties that are recognized by some NWC clients:
} }
``` ```
### Example Hold Invoice Support Flow
1. Client generates a 32-byte hex-encoded preimage.
2. Computes SHA-256 to derive payment hash.
3. Sends `make_hold_invoice` with payment hash and desired parameters.
4. Waits for `hold_invoice_accepted` notification.
5. Upon receiving notification, either:
* Calls `settle_hold_invoice` with the original preimage to release funds, or
* Calls `cancel_hold_invoice` with payment hash to abort.
### Deep-links ### Deep-links
Wallet applications can register deeplinks in mobile systems to make it possible to create a linking UX that doesn't require the user scanning a QR code or pasting some code. Wallet applications can register deeplinks in mobile systems to make it possible to create a linking UX that doesn't require the user scanning a QR code or pasting some code.