Skip to content

NUT-23: BOLT11

optional

depends on: NUT-04 NUT-05


This document describes minting and melting ecash with the bolt11 payment method, which uses Lightning Network invoices. It is an extension of NUT-04 and NUT-05 which cover the protocol steps of minting and melting ecash shared by any supported payment method.

Mint Quote

For the bolt11 method, the wallet includes the following specific PostMintQuoteBolt11Request data:

{
  "amount": <int>,
  "unit": <str_enum[UNIT]>,
  "description": <str> // Optional
}

The mint responds with a PostMintQuoteBolt11Response:

{
  "quote": <str>,
  "request": <str>, // The bolt11 invoice to pay
  "amount": <int>,
  "unit":  <str_enum[UNIT]>,
  "state": <str_enum[STATE]>,
  "expiry": <int|null>
}

state is an enum string field with possible values "UNPAID", "PAID", "ISSUED":

  • "UNPAID" means that the quote's request has not been paid yet.
  • "PAID" means that the request has been paid.
  • "ISSUED" means that the quote has already been issued.

expiry is the Unix timestamp until which the request can be paid (i.e. the bolt11 invoice expiry).

Example

Request with curl:

curl -X POST http://localhost:3338/v1/mint/quote/bolt11 -d '{"amount": 10, "unit": "sat"}' -H "Content-Type: application/json"

Response:

{
  "quote": "DSGLX9kevM...",
  "request": "lnbc100n1pj4apw9...",
  "amount": 10,
  "unit": "sat",
  "state": "UNPAID",
  "expiry": 1701704757
}

Check quote state:

curl -X GET http://localhost:3338/v1/mint/quote/bolt11/DSGLX9kevM...

Minting tokens:

curl -X POST https://mint.host:3338/v1/mint/bolt11 -H "Content-Type: application/json" -d \
'{
  "quote": "DSGLX9kevM...",
  "outputs": [
    {
      "amount": 8,
      "id": "009a1f293253e41e",
      "B_": "035015e6d7ade60ba8426cefaf1832bbd27257636e44a76b922d78e79b47cb689d"
    },
    {
      "amount": 2,
      "id": "009a1f293253e41e",
      "B_": "0288d7649652d0a83fc9c966c969fb217f15904431e61a44b14999fabc1b5d9ac6"
    }
  ]
}'

Response:

{
  "signatures": [
    {
      "id": "009a1f293253e41e",
      "amount": 2,
      "C_": "0224f1c4c564230ad3d96c5033efdc425582397a5a7691d600202732edc6d4b1ec"
    },
    {
      "id": "009a1f293253e41e",
      "amount": 8,
      "C_": "0277d1de806ed177007e5b94a8139343b6382e472c752a74e99949d511f7194f6c"
    }
  ]
}

Mint Settings

A description option MUST be set to indicate whether the bolt11 payment method backend supports providing an invoice description.

Example MintMethodSetting

{
  "method": "bolt11",
  "unit": "sat",
  "min_amount": 0,
  "max_amount": 10000,
  "options": {
    "description": true
  }
}

Melt Quote

For the bolt11 method, the wallet includes the following specific PostMeltQuoteBolt11Request data:

{
  "request": <str>,
  "unit": <str_enum[UNIT]>,
  "options": { // Optional
    "amountless": {
      "amount_msat": <int>
    }
  }
}

Here, request is the bolt11 Lightning invoice to be paid and unit is the unit the wallet would like to pay with. The options field can include support for amountless invoices if supported by the mint.

The mint responds with a PostMeltQuoteBolt11Response:

{
  "quote": <str>,
  "request": <str>,
  "amount": <int>,
  "unit": <str_enum[UNIT]>,
  "fee_reserve": <int>,
  "state": <str_enum[STATE]>,
  "expiry": <int>,
  "payment_preimage": <str|null>
}

Where fee_reserve is the additional fee reserve required for the Lightning payment. The mint expects the wallet to include Proofs of at least total_amount = amount + fee_reserve + fee where fee is calculated from the keyset's input_fee_ppk as described in [NUT-02][02].

Melting Tokens

For the bolt11 method, the wallet can include an optional outputs field in the melt request to receive change for overpaid Lightning fees (see [NUT-08][08]):

{
  "quote": <str>,
  "inputs": <Array[Proof]>,
  "outputs": <Array[BlindedMessage]> // Optional
}

If the outputs field is included and there is excess from the fee_reserve, the mint will respond with a change field containing blind signatures for the overpaid amount:

{
  "quote": <str>,
  "request": <str>,
  "amount": <int>,
  "unit": <str_enum[UNIT]>,
  "fee_reserve": <int>,
  "state": <str_enum[STATE]>,
  "expiry": <int>,
  "payment_preimage": <str>,
  "change": <Array[BlindSignature]> // Present if outputs were included and there's change
}

Example

Melt quote request:

curl -X POST https://mint.host:3338/v1/melt/quote/bolt11 -d \
'{"request": "lnbc100n1p3kdrv5sp5lpdxzghe5j67q...", "unit": "sat"}'

Melt quote response:

{
  "quote": "TRmjduhIsPxd...",
  "request": "lnbc100n1p3kdrv5sp5lpdxzghe5j67q...",
  "amount": 10,
  "unit": "sat",
  "fee_reserve": 2,
  "state": "UNPAID",
  "expiry": 1701704757
}

Check quote state:

curl -X GET http://localhost:3338/v1/melt/quote/bolt11/TRmjduhIsPxd...

Melt request:

curl -X POST https://mint.host:3338/v1/melt/bolt11 -d \
'{"quote": "od4CN5smMMS3K3QVHkbGGNCTxfcAIyIXeq8IrfhP", "inputs": [...]}'

Successful melt response:

{
  "quote": "TRmjduhIsPxd...",
  "request": "lnbc100n1p3kdrv5sp5lpdxzghe5j67q...",
  "amount": 10,
  "unit": "sat",
  "fee_reserve": 2,
  "state": "PAID",
  "expiry": 1701704757,
  "payment_preimage": "c5a1ae1f639e1f4a3872e81500fd028bece7bedc1152f740cba5c3417b748c1b"
}

Example MeltMethodSetting

{
  "method": "bolt11",
  "unit": "sat",
  "min_amount": 100,
  "max_amount": 10000,
  "options": {
    "amountless": true
  }
}