LNURL-Pay

Usage

Rust
// Endpoint can also be of the form:
// lnurlp://domain.com/lnurl-pay?key=val
// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf
let lnurl_pay_url = "lightning@address.com";

if let Ok(LnUrlPay { data: pd }) = parse(lnurl_pay_url).await {
    let amount_msat = pd.min_sendable;
    let optional_comment = Some("<comment>".to_string());
    let optional_payment_label = Some("<label>".to_string());
    let optional_validate_success_action_url = Some(true);

    sdk.lnurl_pay(LnUrlPayRequest {
        data: pd,
        amount_msat,
        comment: optional_comment,
        payment_label: optional_payment_label,
        validate_success_action_url: optional_validate_success_action_url,
    })
    .await?;
}
Swift
// Endpoint can also be of the form:
// lnurlp://domain.com/lnurl-pay?key=val
// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf
var response: LnUrlPayResult?
let lnurlPayUrl = "lightning@address.com"
if let inputType = try? parseInput(s: lnurlPayUrl) {
    if case let .lnUrlPay(data) = inputType {
        let amountMsat = data.minSendable
        let optionalComment = "<comment>"
        let optionalPaymentLabel = "<label>"
        let optionalValidateSuccessActionUrl = true
        let req = LnUrlPayRequest(
            data: data, 
            amountMsat: amountMsat, 
            comment: optionalComment, 
            paymentLabel: optionalPaymentLabel, 
            validateSuccessActionUrl: optionalValidateSuccessActionUrl
        )
        response = try? sdk.payLnurl(req: req)
    }
}
Kotlin
// Endpoint can also be of the form:
// lnurlp://domain.com/lnurl-pay?key=val
// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf
val lnurlPayUrl = "lightning@address.com";
try {
    val inputType = parseInput(lnurlPayUrl)
    if (inputType is InputType.LnUrlPay) {
        val requestData = inputType.data
        val amountMsat = requestData.minSendable
        val optionalComment = "<comment>";
        val optionalPaymentLabel = "<label>";
        val optionalValidateSuccessActionUrl = true;
        val req = LnUrlPayRequest(
            requestData, 
            amountMsat, 
            optionalComment, 
            optionalPaymentLabel, 
            optionalValidateSuccessActionUrl)
        sdk.payLnurl(req)
    }
} catch (e: Exception) {
    // handle error
}
React Native
// Endpoint can also be of the
// lnurlp://domain.com/lnurl-pay?key=val
// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf
try {
  const lnurlPayUrl = 'lightning@address.com'

  const input = await parseInput(lnurlPayUrl)
  if (input.type === InputTypeVariant.LN_URL_PAY) {
    const amountMsat = input.data.minSendable
    const optionalComment = '<comment>'
    const optionalPaymentLabel = '<label>'
    const optionalValidateSuccessActionUrl = true
    const lnUrlPayResult = await payLnurl({
      data: input.data,
      amountMsat,
      comment: optionalComment,
      paymentLabel: optionalPaymentLabel,
      validateSuccessActionUrl: optionalValidateSuccessActionUrl
    })
  }
} catch (err) {
  console.error(err)
}
Dart
/// Endpoint can also be of the form:
/// lnurlp://domain.com/lnurl-pay?key=val
/// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf
String lnurlPayUrl = "lightning@address.com";

InputType inputType = await breezSDK.parseInput(input: lnurlPayUrl);
if (inputType is InputType_LnUrlPay) {
  int amountMsat = inputType.data.minSendable;
  String optionalComment = "<comment>";
  String optionalPaymentLabel = "<label>";
  bool optionalValidateSuccessActionUrl = true;
  LnUrlPayRequest req = LnUrlPayRequest(
    data: inputType.data,
    amountMsat: amountMsat,
    comment: optionalComment,
    paymentLabel: optionalPaymentLabel,
    validateSuccessActionUrl: optionalValidateSuccessActionUrl,
  );
  LnUrlPayResult result = await breezSDK.lnurlPay(req: req);
  print(result.data);
}
Python
# Endpoint can also be of the form:
# lnurlp://domain.com/lnurl-pay?key=val
# lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf
lnurl_pay_url = "lightning@address.com"
try: 
  parsed_input = breez_sdk.parse_input(lnurl_pay_url)
  if isinstance(parsed_input, breez_sdk.InputType.LN_URL_PAY):
     amount_msat = parsed_input.data.min_sendable
     optional_comment = "<comment>"
     optional_payment_label = "<label>"
     optional_validate_success_action_url = True
     req = breez_sdk.LnUrlPayRequest(
        parsed_input.data, 
        amount_msat, 
        optional_comment, 
        optional_payment_label, 
        optional_validate_success_action_url)
     result = sdk_services.pay_lnurl(req)
     return result
except Exception as error:
    print(error)
    raise 
Go
// Endpoint can also be of the form:
// lnurlp://domain.com/lnurl-pay?key=val
// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf
lnurlPayUrl := "lightning@address.com"

if input, err := breez_sdk.ParseInput(lnurlPayUrl); err != nil {
    switch inputType := input.(type) {
    case breez_sdk.InputTypeLnUrlPay:
        amountMsat := inputType.Data.MinSendable
        optionalComment := "<comment>"
        optionalPaymentLabel := "<label>"
        optionalValidateSuccessActionUrl := true
        lnUrlPayRequest := breez_sdk.LnUrlPayRequest{
            Data:                     inputType.Data,
            AmountMsat:               amountMsat,
            Comment:                  &optionalComment,
            PaymentLabel:             &optionalPaymentLabel,
            ValidateSuccessActionUrl: &optionalValidateSuccessActionUrl,
        }
        if result, err := sdk.PayLnurl(lnUrlPayRequest); err != nil {
            switch result.(type) {
            case breez_sdk.LnUrlPayResultEndpointSuccess:
                log.Printf("Successfully paid")
            default:
                log.Printf("Failed to pay")
            }
        }
    }
}
C#
// Endpoint can also be of the form:
// lnurlp://domain.com/lnurl-pay?key=val
// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf
var lnurlPayUrl = "lightning@address.com";

try
{
    var input = BreezSdkMethods.ParseInput(lnurlPayUrl);
    if (input is InputType.LnUrlPay lnurlp)
    {
        var amountMsat = lnurlp.data.minSendable;
        var optionalComment = "<comment>";
        var optionalPaymentLabel = "<label>";
        var optionalValidateSuccessActionUrl = true;
        var req = new LnUrlPayRequest(
            lnurlp.data, 
            amountMsat, 
            optionalComment, 
            optionalPaymentLabel, 
            optionalValidateSuccessActionUrl);
        var result = sdk.PayLnurl(req);
    }
}
catch (Exception)
{
    // Handle error
}

Developer note

By default when the LNURL-pay results in a success action with a URL, the URL is validated to check if there is a mismatch with the LNURL callback domain. You can disable this behaviour by setting the optional validation LnUrlPayPrequest param to false.

Supported Specs

  • LUD-01 LNURL bech32 encoding
  • LUD-06 payRequest spec
  • LUD-09 successAction field for payRequest
  • LUD-16 LN Address
  • LUD-17 Support for lnurlp prefix with non-bech32-encoded LNURL URLs