Sending payments using LNURL-Pay and Lightning address
Preparing LNURL Payments API docs
During the prepare step, the SDK ensures that the inputs are valid with respect to the LNURL-pay request, and also returns the fees related to the payment so they can be confirmed.
Payments can be sent without holding Bitcoin by converting on-the-fly as a step before sending a payment. See Converting tokens for more information.
Setting the receiver amount
When you want the payment recipient to receive a specific amount.
// 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(InputType::LightningAddress(details)) = sdk.parse(lnurl_pay_url).await {
let amount_sats = 5_000;
let optional_comment = Some("<comment>".to_string());
let optional_validate_success_action_url = Some(true);
// Optionally set to use token funds to pay via token conversion
let optional_max_slippage_bps = Some(50);
let optional_completion_timeout_secs = Some(30);
let optional_conversion_options = Some(ConversionOptions {
conversion_type: ConversionType::ToBitcoin {
from_token_identifier: "<token identifier>".to_string(),
},
max_slippage_bps: optional_max_slippage_bps,
completion_timeout_secs: optional_completion_timeout_secs,
});
let prepare_response = sdk
.prepare_lnurl_pay(PrepareLnurlPayRequest {
amount_sats,
pay_request: details.pay_request,
comment: optional_comment,
validate_success_action_url: optional_validate_success_action_url,
conversion_options: optional_conversion_options,
fee_policy: None,
})
.await?;
// If the fees are acceptable, continue to create the LNURL Pay
if let Some(conversion_estimate) = &prepare_response.conversion_estimate {
info!("Estimated conversion amount: {} token base units", conversion_estimate.amount);
info!("Estimated conversion fee: {} token base units", conversion_estimate.fee);
}
let fee_sats = prepare_response.fee_sats;
info!("Fees: {fee_sats} sats");
}
// Endpoint can also be of the form:
// lnurlp://domain.com/lnurl-pay?key=val
// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf
let lnurlPayUrl = "lightning@address.com"
let inputType = try await sdk.parse(input: lnurlPayUrl)
if case .lightningAddress(v1: let details) = inputType {
let amountSats: UInt64 = 5_000
let optionalComment = "<comment>"
let payRequest = details.payRequest
let optionalValidateSuccessActionUrl = true
// Optionally set to use token funds to pay via token conversion
let optionalMaxSlippageBps = UInt32(50)
let optionalCompletionTimeoutSecs = UInt32(30)
let conversionOptions = ConversionOptions(
conversionType: ConversionType.toBitcoin(
fromTokenIdentifier: "<token identifier>"
),
maxSlippageBps: optionalMaxSlippageBps,
completionTimeoutSecs: optionalCompletionTimeoutSecs
)
let request = PrepareLnurlPayRequest(
amountSats: amountSats,
payRequest: payRequest,
comment: optionalComment,
validateSuccessActionUrl: optionalValidateSuccessActionUrl,
conversionOptions: conversionOptions,
feePolicy: nil
)
let prepareResponse = try await sdk.prepareLnurlPay(request: request)
// If the fees are acceptable, continue to create the LNURL Pay
if let conversionEstimate = prepareResponse.conversionEstimate {
print("Estimated conversion amount: \(conversionEstimate.amount) token base units")
print("Estimated conversion fee: \(conversionEstimate.fee) token base units")
}
let feeSats = prepareResponse.feeSats
print("Fees: \(feeSats) sats")
}
// Endpoint can also be of the form:
// lnurlp://domain.com/lnurl-pay?key=val
// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf
val lnurlPayUrl = "lightning@address.com"
try {
val inputType = sdk.parse(lnurlPayUrl)
if (inputType is InputType.LightningAddress) {
val amountSats = 5_000.toULong()
val optionalComment = "<comment>"
val payRequest = inputType.v1.payRequest
val optionalValidateSuccessActionUrl = true
// Optionally set to use token funds to pay via token conversion
val optionalMaxSlippageBps = 50u
val optionalCompletionTimeoutSecs = 30u
val optionalConversionOptions = ConversionOptions(
conversionType = ConversionType.ToBitcoin(
"<token identifier>"
),
maxSlippageBps = optionalMaxSlippageBps,
completionTimeoutSecs = optionalCompletionTimeoutSecs
)
val req = PrepareLnurlPayRequest(
amountSats = amountSats,
payRequest = payRequest,
comment = optionalComment,
validateSuccessActionUrl = optionalValidateSuccessActionUrl,
conversionOptions = optionalConversionOptions,
feePolicy = null,
)
val prepareResponse = sdk.prepareLnurlPay(req)
// If the fees are acceptable, continue to create the LNURL Pay
prepareResponse.conversionEstimate?.let { conversionEstimate ->
// Log.v("Breez", "Estimated conversion amount: ${conversionEstimate.amount} token base units")
// Log.v("Breez", "Estimated conversion fee: ${conversionEstimate.fee} token base units")
}
val feeSats = prepareResponse.feeSats;
// Log.v("Breez", "Fees: ${feeSats} sats")
}
} catch (e: Exception) {
// handle error
}
// Endpoint can also be of the form:
// lnurlp://domain.com/lnurl-pay?key=val
// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43r
// vv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3k
// vdnxx5crxwpjvyunsephsz36jf
var lnurlPayUrl = "lightning@address.com";
var parsedInput = await sdk.Parse(lnurlPayUrl);
if (parsedInput is InputType.LightningAddress lightningAddress)
{
var details = lightningAddress.v1;
var amountSats = 5_000UL;
var optionalComment = "<comment>";
var payRequest = details.payRequest;
var optionalValidateSuccessActionUrl = true;
// Optionally set to use token funds to pay via token conversion
var optionalMaxSlippageBps = 50U;
var optionalCompletionTimeoutSecs = 30U;
var optionalConversionOptions = new ConversionOptions(
conversionType: new ConversionType.ToBitcoin(
fromTokenIdentifier: "<token identifier>"
),
maxSlippageBps: optionalMaxSlippageBps,
completionTimeoutSecs: optionalCompletionTimeoutSecs
);
var request = new PrepareLnurlPayRequest(
amountSats: amountSats,
payRequest: payRequest,
comment: optionalComment,
validateSuccessActionUrl: optionalValidateSuccessActionUrl,
conversionOptions: optionalConversionOptions,
feePolicy: null
);
var prepareResponse = await sdk.PrepareLnurlPay(request: request);
// If the fees are acceptable, continue to create the LNURL Pay
if (prepareResponse.conversionEstimate != null)
{
Console.WriteLine("Estimated conversion amount: " +
$"{prepareResponse.conversionEstimate.amount} token base units");
Console.WriteLine("Estimated conversion fee: " +
$"{prepareResponse.conversionEstimate.fee} token base units");
}
var feeSats = prepareResponse.feeSats;
Console.WriteLine($"Fees: {feeSats} sats");
}
// Endpoint can also be of the form:
// lnurlp://domain.com/lnurl-pay?key=val
// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf
const lnurlPayUrl = 'lightning@address.com'
const input = await sdk.parse(lnurlPayUrl)
if (input.type === 'lightningAddress') {
const amountSats = 5_000
const optionalComment = '<comment>'
const payRequest = input.payRequest
const optionalValidateSuccessActionUrl = true
// Optionally set to use token funds to pay via token conversion
const optionalMaxSlippageBps = 50
const optionalCompletionTimeoutSecs = 30
const optionalConversionOptions: ConversionOptions = {
conversionType: {
type: 'toBitcoin',
fromTokenIdentifier: '<token identifier>'
},
maxSlippageBps: optionalMaxSlippageBps,
completionTimeoutSecs: optionalCompletionTimeoutSecs
}
const prepareResponse = await sdk.prepareLnurlPay({
amountSats,
payRequest,
comment: optionalComment,
validateSuccessActionUrl: optionalValidateSuccessActionUrl,
conversionOptions: optionalConversionOptions,
feePolicy: undefined
})
// If the fees are acceptable, continue to create the LNURL Pay
if (prepareResponse.conversionEstimate !== undefined) {
const conversionEstimate = prepareResponse.conversionEstimate
console.debug(`Estimated conversion amount: ${conversionEstimate.amount} token base units`)
console.debug(`Estimated conversion fee: ${conversionEstimate.fee} token base units`)
}
const feeSats = prepareResponse.feeSats
console.log(`Fees: ${feeSats} sats`)
}
// Endpoint can also be of the form:
// lnurlp://domain.com/lnurl-pay?key=val
// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf
const lnurlPayUrl = 'lightning@address.com'
const input = await sdk.parse(lnurlPayUrl)
if (input.tag === InputType_Tags.LightningAddress) {
const amountSats = BigInt(5_000)
const optionalComment = '<comment>'
const payRequest = input.inner[0].payRequest
const optionalValidateSuccessActionUrl = true
// Optionally set to use token funds to pay via token conversion
const optionalMaxSlippageBps = 50
const optionalCompletionTimeoutSecs = 30
const optionalConversionOptions = {
conversionType: new ConversionType.ToBitcoin({
fromTokenIdentifier: '<token identifier>'
}),
maxSlippageBps: optionalMaxSlippageBps,
completionTimeoutSecs: optionalCompletionTimeoutSecs
}
const prepareResponse = await sdk.prepareLnurlPay({
amountSats,
payRequest,
comment: optionalComment,
validateSuccessActionUrl: optionalValidateSuccessActionUrl,
conversionOptions: optionalConversionOptions,
feePolicy: undefined
})
// If the fees are acceptable, continue to create the LNURL Pay
if (prepareResponse.conversionEstimate !== undefined) {
const conversionEstimate = prepareResponse.conversionEstimate
console.debug(`Estimated conversion amount: ${conversionEstimate.amount} token base units`)
console.debug(`Estimated conversion fee: ${conversionEstimate.fee} token base units`)
}
const feeSats = prepareResponse.feeSats
console.log(`Fees: ${feeSats} sats`)
}
// Endpoint can also be of the form:
// lnurlp://domain.com/lnurl-pay?key=val
// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf
String lnurlPayUrl = "lightning@address.com";
InputType inputType = await sdk.parse(input: lnurlPayUrl);
if (inputType is InputType_LightningAddress) {
BigInt amountSats = BigInt.from(5000);
String optionalComment = "<comment>";
bool optionalValidateSuccessActionUrl = true;
// Optionally set to use token funds to pay via token conversion
int optionalMaxSlippageBps = 50;
int optionalCompletionTimeoutSecs = 30;
final optionalConversionOptions = ConversionOptions(
conversionType: ConversionType.toBitcoin(
fromTokenIdentifier: "<token identifier>",
),
maxSlippageBps: optionalMaxSlippageBps,
completionTimeoutSecs: optionalCompletionTimeoutSecs,
);
PrepareLnurlPayRequest request = PrepareLnurlPayRequest(
amountSats: amountSats,
payRequest: inputType.field0.payRequest,
comment: optionalComment,
validateSuccessActionUrl: optionalValidateSuccessActionUrl,
conversionOptions: optionalConversionOptions,
feePolicy: null,
);
PrepareLnurlPayResponse prepareResponse =
await sdk.prepareLnurlPay(request: request);
// If the fees are acceptable, continue to create the LNURL Pay
if (prepareResponse.conversionEstimate != null) {
print(
"Estimated conversion amount: ${prepareResponse.conversionEstimate!.amount} token base units");
print(
"Estimated conversion fee: ${prepareResponse.conversionEstimate!.fee} token base units");
}
BigInt feeSats = prepareResponse.feeSats;
print("Fees: $feeSats sats");
}
# Endpoint can also be of the form:
# lnurlp://domain.com/lnurl-pay?key=val
# lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43r
# vv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3k
# vdnxx5crxwpjvyunsephsz36jf
lnurl_pay_url = "lightning@address.com"
try:
parsed_input = await sdk.parse(lnurl_pay_url)
if isinstance(parsed_input, InputType.LIGHTNING_ADDRESS):
details = parsed_input[0]
amount_sats = 5_000
optional_comment = "<comment>"
pay_request = details.pay_request
optional_validate_success_action_url = True
# Optionally set to use token funds to pay via token conversion
optional_max_slippage_bps = 50
optional_completion_timeout_secs = 30
optional_conversion_options = ConversionOptions(
conversion_type=ConversionType.TO_BITCOIN(
from_token_identifier="<token identifier>"
),
max_slippage_bps=optional_max_slippage_bps,
completion_timeout_secs=optional_completion_timeout_secs,
)
request = PrepareLnurlPayRequest(
amount_sats=amount_sats,
pay_request=pay_request,
comment=optional_comment,
validate_success_action_url=optional_validate_success_action_url,
conversion_options=optional_conversion_options,
fee_policy=None,
)
prepare_response = await sdk.prepare_lnurl_pay(request=request)
# If the fees are acceptable, continue to create the LNURL Pay
if prepare_response.conversion_estimate is not None:
conversion_estimate = prepare_response.conversion_estimate
logging.debug(
f"Estimated conversion amount: {conversion_estimate.amount} token base units"
)
logging.debug(
f"Estimated conversion fee: {conversion_estimate.fee} token base units"
)
logging.debug(f"Fees: {prepare_response.fee_sats} sats")
return prepare_response
except Exception as error:
logging.error(error)
raise
// Endpoint can also be of the form:
// lnurlp://domain.com/lnurl-pay?key=val
// lnurl1dp68gurn8ghj7mr0vdskc6r0wd6z7mrww4excttsv9un7um9wdekjmmw84jxywf5x43rvv35xgmr2enrxanr2cfcvsmnwe3jxcukvde48qukgdec89snwde3vfjxvepjxpjnjvtpxd3kvdnxx5crxwpjvyunsephsz36jf
lnurlPayUrl := "lightning@address.com"
input, err := sdk.Parse(lnurlPayUrl)
if err != nil {
var sdkErr *breez_sdk_spark.SdkError
if errors.As(err, &sdkErr) {
// Handle SdkError - can inspect specific variants if needed
// e.g., switch on sdkErr variant for InsufficientFunds, NetworkError, etc.
}
return nil, err
}
switch inputType := input.(type) {
case breez_sdk_spark.InputTypeLightningAddress:
amountSats := uint64(5_000)
optionalComment := "<comment>"
optionalValidateSuccessActionUrl := true
// Optionally set to use token funds to pay via token conversion
optionalMaxSlippageBps := uint32(50)
optionalCompletionTimeoutSecs := uint32(30)
optionalConversionOptions := breez_sdk_spark.ConversionOptions{
ConversionType: breez_sdk_spark.ConversionTypeToBitcoin{
FromTokenIdentifier: "<token identifier>",
},
MaxSlippageBps: &optionalMaxSlippageBps,
CompletionTimeoutSecs: &optionalCompletionTimeoutSecs,
}
request := breez_sdk_spark.PrepareLnurlPayRequest{
AmountSats: amountSats,
PayRequest: inputType.Field0.PayRequest,
Comment: &optionalComment,
ValidateSuccessActionUrl: &optionalValidateSuccessActionUrl,
ConversionOptions: &optionalConversionOptions,
FeePolicy: nil,
}
prepareResponse, err := sdk.PrepareLnurlPay(request)
if err != nil {
var sdkErr *breez_sdk_spark.SdkError
if errors.As(err, &sdkErr) {
// Handle SdkError - can inspect specific variants if needed
// e.g., switch on sdkErr variant for InsufficientFunds, NetworkError, etc.
}
return nil, err
}
// If the fees are acceptable, continue to create the LNURL Pay
if prepareResponse.ConversionEstimate != nil {
log.Printf("Estimated conversion amount: %v token base units", prepareResponse.ConversionEstimate.Amount)
log.Printf("Estimated conversion fee: %v token base units", prepareResponse.ConversionEstimate.Fee)
}
feeSats := prepareResponse.FeeSats
log.Printf("Fees: %v sats", feeSats)
return &prepareResponse, nil
}
Setting the fee policy
By default, fees are added on top of the amount (FeePolicy::FeesExcludedFeePolicy.FEES_EXCLUDEDFeePolicy.feesExcludedFeePolicy.FeesExcludedFeePolicy.FeesExcludedFeePolicy.FeesExcludedFeePolicy.FeesExcludedFeePolicyFeesExcludedFeePolicy.FeesExcluded). Use FeePolicy::FeesIncludedFeePolicy.FEES_INCLUDEDFeePolicy.feesIncludedFeePolicy.FeesIncludedFeePolicy.FeesIncludedFeePolicy.FeesIncludedFeePolicy.FeesIncludedFeePolicyFeesIncludedFeePolicy.FeesIncluded to deduct fees from the amount instead—the receiver gets the amount minus fees.
This is particularly useful when you want to spend your entire balance in a single payment—simply provide your full balance as the amount.
// By default (FeePolicy::FeesExcluded), fees are added on top of the amount.
// Use FeePolicy::FeesIncluded to deduct fees from the amount instead.
// The receiver gets amount minus fees.
let optional_comment = Some("<comment>".to_string());
let optional_validate_success_action_url = Some(true);
let amount_sats = 5_000;
let prepare_response = sdk
.prepare_lnurl_pay(PrepareLnurlPayRequest {
amount_sats,
pay_request,
comment: optional_comment,
validate_success_action_url: optional_validate_success_action_url,
conversion_options: None,
fee_policy: Some(FeePolicy::FeesIncluded),
})
.await?;
// If the fees are acceptable, continue to create the LNURL Pay
let fee_sats = prepare_response.fee_sats;
info!("Fees: {fee_sats} sats");
// The receiver gets amount_sats - fee_sats
// By default (.feesExcluded), fees are added on top of the amount.
// Use .feesIncluded to deduct fees from the amount instead.
// The receiver gets amount minus fees.
let amountSats: UInt64 = 5_000
let optionalComment = "<comment>"
let optionalValidateSuccessActionUrl = true
let request = PrepareLnurlPayRequest(
amountSats: amountSats,
payRequest: payRequest,
comment: optionalComment,
validateSuccessActionUrl: optionalValidateSuccessActionUrl,
conversionOptions: nil,
feePolicy: .feesIncluded
)
let response = try await sdk.prepareLnurlPay(request: request)
// If the fees are acceptable, continue to create the LNURL Pay
let feeSats = response.feeSats
print("Fees: \(feeSats) sats")
// The receiver gets amountSats - feeSats
// By default (FeePolicy.FEES_EXCLUDED), fees are added on top of the amount.
// Use FeePolicy.FEES_INCLUDED to deduct fees from the amount instead.
// The receiver gets amount minus fees.
val optionalComment = "<comment>"
val optionalValidateSuccessActionUrl = true
val amountSats = 5_000.toULong()
val req = PrepareLnurlPayRequest(
amountSats = amountSats,
payRequest = payRequest,
comment = optionalComment,
validateSuccessActionUrl = optionalValidateSuccessActionUrl,
conversionOptions = null,
feePolicy = FeePolicy.FEES_INCLUDED,
)
val prepareResponse = sdk.prepareLnurlPay(req)
// If the fees are acceptable, continue to create the LNURL Pay
val feeSats = prepareResponse.feeSats
// Log.v("Breez", "Fees: ${feeSats} sats")
// The receiver gets amountSats - feeSats
// By default (FeePolicy.FeesExcluded), fees are added on top of the amount.
// Use FeePolicy.FeesIncluded to deduct fees from the amount instead.
// The receiver gets amount minus fees.
var amountSats = 5_000UL;
var optionalComment = "<comment>";
var optionalValidateSuccessActionUrl = true;
var request = new PrepareLnurlPayRequest(
amountSats: amountSats,
payRequest: payRequest,
comment: optionalComment,
validateSuccessActionUrl: optionalValidateSuccessActionUrl,
conversionOptions: null,
feePolicy: FeePolicy.FeesIncluded
);
var prepareResponse = await sdk.PrepareLnurlPay(request: request);
// If the fees are acceptable, continue to create the LNURL Pay
var feeSats = prepareResponse.feeSats;
Console.WriteLine($"Fees: {feeSats} sats");
// The receiver gets amountSats - feeSats
// By default ({ type: 'feesExcluded' }), fees are added on top of the amount.
// Use { type: 'feesIncluded' } to deduct fees from the amount instead.
// The receiver gets amount minus fees.
const optionalComment = '<comment>'
const optionalValidateSuccessActionUrl = true
const amountSats = 5_000
const feePolicy: FeePolicy = 'feesIncluded'
const prepareResponse = await sdk.prepareLnurlPay({
amountSats,
payRequest,
comment: optionalComment,
validateSuccessActionUrl: optionalValidateSuccessActionUrl,
conversionOptions: undefined,
feePolicy
})
// If the fees are acceptable, continue to create the LNURL Pay
const feeSats = prepareResponse.feeSats
console.log(`Fees: ${feeSats} sats`)
// The receiver gets amountSats - feeSats
// By default (FeePolicy.FeesExcluded), fees are added on top of the amount.
// Use FeePolicy.FeesIncluded to deduct fees from the amount instead.
// The receiver gets amount minus fees.
const optionalComment = '<comment>'
const optionalValidateSuccessActionUrl = true
const amountSats = BigInt(5_000)
const prepareResponse = await sdk.prepareLnurlPay({
amountSats,
payRequest,
comment: optionalComment,
validateSuccessActionUrl: optionalValidateSuccessActionUrl,
conversionOptions: undefined,
feePolicy: FeePolicy.FeesIncluded
})
// If the fees are acceptable, continue to create the LNURL Pay
const feeSats = prepareResponse.feeSats
console.log(`Fees: ${feeSats} sats`)
// The receiver gets amountSats - feeSats
// By default (FeePolicy.feesExcluded), fees are added on top of the amount.
// Use FeePolicy.feesIncluded to deduct fees from the amount instead.
// The receiver gets amount minus fees.
String optionalComment = "<comment>";
bool optionalValidateSuccessActionUrl = true;
BigInt amountSats = BigInt.from(5000);
PrepareLnurlPayRequest request = PrepareLnurlPayRequest(
amountSats: amountSats,
payRequest: payRequest,
comment: optionalComment,
validateSuccessActionUrl: optionalValidateSuccessActionUrl,
conversionOptions: null,
feePolicy: FeePolicy.feesIncluded,
);
PrepareLnurlPayResponse prepareResponse =
await sdk.prepareLnurlPay(request: request);
// If the fees are acceptable, continue to create the LNURL Pay
BigInt feeSats = prepareResponse.feeSats;
print("Fees: $feeSats sats");
// The receiver gets amountSats - feeSats
# By default (FeePolicy.FEES_EXCLUDED), fees are added on top of the amount.
# Use FeePolicy.FEES_INCLUDED to deduct fees from the amount instead.
# The receiver gets amount minus fees.
amount_sats = 5_000
optional_comment = "<comment>"
optional_validate_success_action_url = True
request = PrepareLnurlPayRequest(
amount_sats=amount_sats,
pay_request=pay_request,
comment=optional_comment,
validate_success_action_url=optional_validate_success_action_url,
conversion_options=None,
fee_policy=FeePolicy.FEES_INCLUDED,
)
prepare_response = await sdk.prepare_lnurl_pay(request=request)
# If the fees are acceptable, continue to create the LNURL Pay
fee_sats = prepare_response.fee_sats
logging.debug(f"Fees: {fee_sats} sats")
# The receiver gets amount_sats - fee_sats
// By default (FeePolicyFeesExcluded), fees are added on top of the amount.
// Use FeePolicyFeesIncluded to deduct fees from the amount instead.
// The receiver gets amount minus fees.
amountSats := uint64(5_000)
optionalComment := "<comment>"
optionalValidateSuccessActionUrl := true
feePolicy := breez_sdk_spark.FeePolicyFeesIncluded
request := breez_sdk_spark.PrepareLnurlPayRequest{
AmountSats: amountSats,
PayRequest: payRequest,
Comment: &optionalComment,
ValidateSuccessActionUrl: &optionalValidateSuccessActionUrl,
ConversionOptions: nil,
FeePolicy: &feePolicy,
}
response, err := sdk.PrepareLnurlPay(request)
if err != nil {
return nil, err
}
// If the fees are acceptable, continue to create the LNURL Pay
feeSats := response.FeeSats
log.Printf("Fees: %v sats", feeSats)
// The receiver gets amountSats - feeSats
LNURL Payments API docs
Once the payment has been prepared and the fees are accepted, the payment can be sent by passing:
- Prepare Response - The response from the Preparing LNURL Payments step.
- Idempotency Key - An optional UUID that identifies the payment. If set, providing the same idempotency key for multiple requests will ensure that only one payment is made.
let optional_idempotency_key = Some("<idempotency key uuid>".to_string());
let response = sdk
.lnurl_pay(LnurlPayRequest {
prepare_response,
idempotency_key: optional_idempotency_key,
})
.await?;
let optionalIdempotencyKey = "<idempotency key uuid>"
let response = try await sdk.lnurlPay(
request: LnurlPayRequest(
prepareResponse: prepareResponse,
idempotencyKey: optionalIdempotencyKey
))
try {
val optionalIdempotencyKey = "<idempotency key uuid>"
val response = sdk.lnurlPay(LnurlPayRequest(prepareResponse, optionalIdempotencyKey))
} catch (e: Exception) {
// handle error
}
var optionalIdempotencyKey = "<idempotency key uuid>";
var response = await sdk.LnurlPay(
new LnurlPayRequest(
prepareResponse: prepareResponse,
idempotencyKey: optionalIdempotencyKey
)
);
const optionalIdempotencyKey = '<idempotency key uuid>'
const response = await sdk.lnurlPay({
prepareResponse,
idempotencyKey: optionalIdempotencyKey
})
const optionalIdempotencyKey = '<idempotency key uuid>'
const response = await sdk.lnurlPay({
prepareResponse,
idempotencyKey: optionalIdempotencyKey
})
String? optionalIdempotencyKey = "<idempotency key uuid>";
LnurlPayResponse response = await sdk.lnurlPay(
request: LnurlPayRequest(
prepareResponse: prepareResponse,
idempotencyKey: optionalIdempotencyKey),
);
try:
optional_idempotency_key = "<idempotency key uuid>"
response = await sdk.lnurl_pay(
LnurlPayRequest(
prepare_response=prepare_response,
idempotency_key=optional_idempotency_key,
)
)
except Exception as error:
logging.error(error)
raise
optionalIdempotencyKey := "<idempotency key uuid>"
request := breez_sdk_spark.LnurlPayRequest{
PrepareResponse: prepareResponse,
IdempotencyKey: &optionalIdempotencyKey,
}
response, err := sdk.LnurlPay(request)
if err != nil {
var sdkErr *breez_sdk_spark.SdkError
if errors.As(err, &sdkErr) {
// Handle SdkError - can inspect specific variants if needed
// e.g., switch on sdkErr variant for InsufficientFunds, NetworkError, etc.
}
return nil, err
}
payment := response.Payment
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 validationPrepareLnurlPayRequest param to false.