Receiving payments
With the Breez SDK you aren't required to open a channel and set up your inbound liquidity.
Once the SDK is initialized, you can directly begin receiving payments. The receive process takes two steps:
Developer note
Consider implementing the Notification Plugin when using the Breez SDK in a mobile application. By registering a webhook the application can receive notifications to process the payment in the background.Preparing Payments API docs
During the prepare step, the SDK ensures that the inputs are valid with respect to the specified payment method, and also returns the relative fees related to the payment so they can be confirmed.
The SDK currently supports three methods of receiving: Lightning, Bitcoin and Liquid:
Lightning
When receiving via Lightning, we generate an invoice to be paid. Note that the payment may fallback to a direct Liquid payment (if the payer's client supports this).
Note: The amount field is currently mandatory when paying via Lightning.
// Fetch the Receive lightning limits
let current_limits = sdk.fetch_lightning_limits().await?;
info!("Minimum amount: {} sats", current_limits.receive.min_sat);
info!("Maximum amount: {} sats", current_limits.receive.max_sat);
// Set the invoice amount you wish the payer to send, which should be within the above limits
let optional_amount = Some(ReceiveAmount::Bitcoin {
payer_amount_sat: 5_000,
});
let prepare_response = sdk
.prepare_receive_payment(&PrepareReceiveRequest {
payment_method: PaymentMethod::Lightning,
amount: optional_amount,
})
.await?;
// If the fees are acceptable, continue to create the Receive Payment
let receive_fees_sat = prepare_response.fees_sat;
info!("Fees: {} sats", receive_fees_sat);
// Fetch the Receive lightning limits
let currentLimits = try? sdk.fetchLightningLimits()
print("Minimum amount: {} sats", currentLimits?.receive.minSat ?? 0);
print("Maximum amount: {} sats", currentLimits?.receive.maxSat ?? 0);
// Set the invoice amount you wish the payer to send, which should be within the above limits
let optionalAmount = ReceiveAmount.bitcoin(payerAmountSat: 5_000)
let prepareResponse = try? sdk
.prepareReceivePayment(req: PrepareReceiveRequest(
paymentMethod: PaymentMethod.lightning,
amount: optionalAmount
));
// If the fees are acceptable, continue to create the Receive Payment
let receiveFeesSat = prepareResponse!.feesSat;
print("Fees: {} sats", receiveFeesSat);
try {
// Fetch the lightning Receive limits
val currentLimits = sdk.fetchLightningLimits()
// Log.v("Breez", "Minimum amount allowed to deposit in sats: ${currentLimits.receive.minSat}")
// Log.v("Breez", "Maximum amount allowed to deposit in sats: ${currentLimits.receive.maxSat}")
// Set the invoice amount you wish the payer to send, which should be within the above limits
val optionalAmount = ReceiveAmount.Bitcoin(5_000.toULong())
val prepareRequest = PrepareReceiveRequest(PaymentMethod.LIGHTNING, optionalAmount)
val prepareResponse = sdk.prepareReceivePayment(prepareRequest)
// If the fees are acceptable, continue to create the Receive Payment
val receiveFeesSat = prepareResponse.feesSat;
// Log.v("Breez", "Fees: ${receiveFeesSat} sats")
} catch (e: Exception) {
// handle error
}
// Fetch the Receive lightning limits
const currentLimits = await fetchLightningLimits()
console.log(`Minimum amount, in sats: ${currentLimits.receive.minSat}`)
console.log(`Maximum amount, in sats: ${currentLimits.receive.maxSat}`)
// Set the amount you wish the payer to send via lightning, which should be within the above limits
const optionalAmount: ReceiveAmount = {
type: ReceiveAmountVariant.BITCOIN,
payerAmountSat: 5_000
}
const prepareResponse = await prepareReceivePayment({
paymentMethod: PaymentMethod.LIGHTNING,
amount: optionalAmount
})
// If the fees are acceptable, continue to create the Receive Payment
const receiveFeesSat = prepareResponse.feesSat
console.log(`Fees: ${receiveFeesSat} sats`)
// Fetch the Receive lightning limits
LightningPaymentLimitsResponse currentLightningLimits =
await breezSDKLiquid.instance!.fetchLightningLimits();
print("Minimum amount: ${currentLightningLimits.receive.minSat} sats");
print("Maximum amount: ${currentLightningLimits.receive.maxSat} sats");
// Create an invoice and set the amount you wish the payer to send
ReceiveAmount_Bitcoin optionalAmount = ReceiveAmount_Bitcoin(payerAmountSat: 5000 as BigInt);
PrepareReceiveResponse prepareResponse = await breezSDKLiquid.instance!.prepareReceivePayment(
req: PrepareReceiveRequest(
paymentMethod: PaymentMethod.lightning,
amount: optionalAmount,
),
);
// If the fees are acceptable, continue to create the Receive Payment
BigInt receiveFeesSat = prepareResponse.feesSat;
print("Fees: $receiveFeesSat sats");
try:
# Fetch the lightning Receive limits
current_limits = sdk.fetch_lightning_limits()
logging.debug("Minimum amount allowed to deposit in sats ", current_limits.receive.min_sat)
logging.debug("Maximum amount allowed to deposit in sats ", current_limits.receive.max_sat)
# Set the invoice amount you wish the payer to send, which should be within the above limits
optional_amount = ReceiveAmount.BITCOIN(5_000)
prepare_request = PrepareReceiveRequest(PaymentMethod.LIGHTNING, optional_amount)
prepare_response = sdk.prepare_receive_payment(prepare_request)
# If the fees are acceptable, continue to create the Receive Payment
receive_fees_sat = prepare_response.fees_sat
logging.debug("Fees: ", receive_fees_sat, " sats")
return prepare_response
except Exception as error:
logging.error(error)
raise
// Fetch the lightning Receive limits
if currentLimits, err := sdk.FetchLightningLimits(); err == nil {
log.Printf("Minimum amount, in sats: %v", currentLimits.Receive.MinSat)
log.Printf("Maximum amount, in sats: %v", currentLimits.Receive.MaxSat)
}
// Set the invoice amount you wish the payer to send, which should be within the above limits
var optionalAmount breez_sdk_liquid.ReceiveAmount = breez_sdk_liquid.ReceiveAmountBitcoin{
PayerAmountSat: uint64(5_000),
}
prepareRequest := breez_sdk_liquid.PrepareReceiveRequest{
PaymentMethod: breez_sdk_liquid.PaymentMethodLightning,
Amount: &optionalAmount,
}
if prepareResponse, err := sdk.PrepareReceivePayment(prepareRequest); err == nil {
// If the fees are acceptable, continue to create the Receive Payment
receiveFeesSat := prepareResponse.FeesSat
log.Printf("Fees: %v sats", receiveFeesSat)
}
try
{
// Fetch the lightning Receive limits
var currentLimits = sdk.FetchLightningLimits();
Console.WriteLine($"Minimum amount allowed to deposit in sats: {currentLimits.receive.minSat}");
Console.WriteLine($"Maximum amount allowed to deposit in sats: {currentLimits.receive.maxSat}");
// Set the invoice amount you wish the payer to send, which should be within the above limits
var optionalAmount = new ReceiveAmount.Bitcoin(5000);
var prepareRequest = new PrepareReceiveRequest(PaymentMethod.Lightning, optionalAmount);
var prepareResponse = sdk.PrepareReceivePayment(prepareRequest);
// If the fees are acceptable, continue to create the Receive Payment
var receiveFeesSat = prepareResponse.feesSat;
Console.WriteLine($"Fees: {receiveFeesSat} sats");
}
catch (Exception)
{
// Handle error
}
Bitcoin
When receiving via Bitcoin, we generate a Bitcoin BIP21 URI to be paid.
The amount
field is optional when preparing a Bitcoin payment. However, if no amount is provided, the returned fees will only be an estimation. This is because:
- The fees have an amount-dependent component that can only be determined once the sender initiates the payment
- The fees also depend on current onchain fee conditions, which may change between the time of preparation and actual payment
If the onchain fee rate increases between preparation and payment time, the payment will be put on hold until the user explicitly confirms the new fees. To learn more about this, see the Amountless Bitcoin Payments section below.
// Fetch the Receive onchain limits
let current_limits = sdk.fetch_onchain_limits().await?;
info!("Minimum amount: {} sats", current_limits.receive.min_sat);
info!("Maximum amount: {} sats", current_limits.receive.max_sat);
// Set the onchain amount you wish the payer to send, which should be within the above limits
let optional_amount = Some(ReceiveAmount::Bitcoin {
payer_amount_sat: 5_000,
});
let prepare_response = sdk
.prepare_receive_payment(&PrepareReceiveRequest {
payment_method: PaymentMethod::BitcoinAddress,
amount: optional_amount,
})
.await?;
// If the fees are acceptable, continue to create the Receive Payment
let receive_fees_sat = prepare_response.fees_sat;
info!("Fees: {} sats", receive_fees_sat);
// Fetch the Receive onchain limits
let currentLimits = try? sdk.fetchOnchainLimits()
print("Minimum amount: {} sats", currentLimits?.receive.minSat ?? 0);
print("Maximum amount: {} sats", currentLimits?.receive.maxSat ?? 0);
// Set the onchain amount you wish the payer to send, which should be within the above limits
let optionalAmount = ReceiveAmount.bitcoin(payerAmountSat: 5_000)
let prepareResponse = try? sdk
.prepareReceivePayment(req: PrepareReceiveRequest(
paymentMethod: PaymentMethod.bitcoinAddress,
amount: optionalAmount
));
// If the fees are acceptable, continue to create the Receive Payment
let receiveFeesSat = prepareResponse!.feesSat;
print("Fees: {} sats", receiveFeesSat);
try {
// Fetch the onchain Receive limits
val currentLimits = sdk.fetchOnchainLimits()
// Log.v("Breez", "Minimum amount allowed to deposit in sats: ${currentLimits.receive.minSat}")
// Log.v("Breez", "Maximum amount allowed to deposit in sats: ${currentLimits.receive.maxSat}")
// Set the onchain amount you wish the payer to send, which should be within the above limits
val optionalAmount = ReceiveAmount.Bitcoin(5_000.toULong())
val prepareRequest = PrepareReceiveRequest(PaymentMethod.BITCOIN_ADDRESS, optionalAmount)
val prepareResponse = sdk.prepareReceivePayment(prepareRequest)
// If the fees are acceptable, continue to create the Receive Payment
val receiveFeesSat = prepareResponse.feesSat;
// Log.v("Breez", "Fees: ${receiveFeesSat} sats")
} catch (e: Exception) {
// handle error
}
// Fetch the Onchain lightning limits
const currentLimits = await fetchOnchainLimits()
console.log(`Minimum amount, in sats: ${currentLimits.receive.minSat}`)
console.log(`Maximum amount, in sats: ${currentLimits.receive.maxSat}`)
// Set the onchain amount you wish the payer to send, which should be within the above limits
const optionalAmount: ReceiveAmount = {
type: ReceiveAmountVariant.BITCOIN,
payerAmountSat: 5_000
}
const prepareResponse = await prepareReceivePayment({
paymentMethod: PaymentMethod.BITCOIN_ADDRESS,
amount: optionalAmount
})
// If the fees are acceptable, continue to create the Receive Payment
const receiveFeesSat = prepareResponse.feesSat
console.log(`Fees: ${receiveFeesSat} sats`)
// Fetch the Receive onchain limits
OnchainPaymentLimitsResponse currentOnchainLimits = await breezSDKLiquid.instance!.fetchOnchainLimits();
print("Minimum amount: ${currentOnchainLimits.receive.minSat} sats");
print("Maximum amount: ${currentOnchainLimits.receive.maxSat} sats");
// Or create a cross-chain transfer (Liquid to Bitcoin) via chain swap
ReceiveAmount_Bitcoin optionalAmount = ReceiveAmount_Bitcoin(payerAmountSat: 5000 as BigInt);
PrepareReceiveResponse prepareResponse = await breezSDKLiquid.instance!.prepareReceivePayment(
req: PrepareReceiveRequest(
paymentMethod: PaymentMethod.bitcoinAddress,
amount: optionalAmount,
),
);
// If the fees are acceptable, continue to create the Receive Payment
BigInt receiveFeesSat = prepareResponse.feesSat;
print("Fees: $receiveFeesSat sats");
try:
# Fetch the onchain Receive limits
current_limits = sdk.fetch_onchain_limits()
logging.debug("Minimum amount allowed to deposit in sats ", current_limits.receive.min_sat)
logging.debug("Maximum amount allowed to deposit in sats ", current_limits.receive.max_sat)
# Set the onchain amount you wish the payer to send, which should be within the above limits
optional_amount = ReceiveAmount.BITCOIN(5_000)
prepare_request = PrepareReceiveRequest(PaymentMethod.BITCOIN_ADDRESS, optional_amount)
prepare_response = sdk.prepare_receive_payment(prepare_request)
# If the fees are acceptable, continue to create the Receive Payment
receive_fees_sat = prepare_response.fees_sat
logging.debug("Fees: ", receive_fees_sat, " sats")
return prepare_response
except Exception as error:
logging.error(error)
raise
// Fetch the onchain Receive limits
if currentLimits, err := sdk.FetchOnchainLimits(); err == nil {
log.Printf("Minimum amount, in sats: %v", currentLimits.Receive.MinSat)
log.Printf("Maximum amount, in sats: %v", currentLimits.Receive.MaxSat)
}
// Set the onchain amount you wish the payer to send, which should be within the above limits
var optionalAmount breez_sdk_liquid.ReceiveAmount = breez_sdk_liquid.ReceiveAmountBitcoin{
PayerAmountSat: uint64(5_000),
}
prepareRequest := breez_sdk_liquid.PrepareReceiveRequest{
PaymentMethod: breez_sdk_liquid.PaymentMethodBitcoinAddress,
Amount: &optionalAmount,
}
if prepareResponse, err := sdk.PrepareReceivePayment(prepareRequest); err == nil {
// If the fees are acceptable, continue to create the Receive Payment
receiveFeesSat := prepareResponse.FeesSat
log.Printf("Fees: %v sats", receiveFeesSat)
}
try
{
// Fetch the onchain Receive limits
var currentLimits = sdk.FetchOnchainLimits();
Console.WriteLine($"Minimum amount allowed to deposit in sats: {currentLimits.receive.minSat}");
Console.WriteLine($"Maximum amount allowed to deposit in sats: {currentLimits.receive.maxSat}");
// Set the onchain amount you wish the payer to send, which should be within the above limits
var optionalAmount = new ReceiveAmount.Bitcoin(5000);
var prepareRequest = new PrepareReceiveRequest(PaymentMethod.BitcoinAddress, optionalAmount);
var prepareResponse = sdk.PrepareReceivePayment(prepareRequest);
// If the fees are acceptable, continue to create the Receive Payment
var receiveFeesSat = prepareResponse.feesSat;
Console.WriteLine($"Fees: {receiveFeesSat} sats");
}
catch (Exception)
{
// Handle error
}
Developer note
The above checks include validating against maximum and minimum limits. Even when no specific amount is provided, the amount transferred to the swap address must still fall within these limits. Your application's users must be informed of these limits because if the amount transferred falls outside this valid range, the funds will not be successfully received via the normal swap flow. In such cases, a manual refund will be necessary. For further instructions on how to execute a manual refund, see the section on refunding payments.
Liquid
When receiving via Liquid, we can either generate an address to receive to, or a BIP21 URI with information regarding the payment (currently only the amount and message).
To generate a BIP21 address, all you have to do is specify a payer amount.
Developer note
To receive non-Bitcoin assets, see Handling multiple assets.// Create a Liquid BIP21 URI/address to receive a payment to.
// There are no limits, but the payer amount should be greater than broadcast fees when specified
// Note: Not setting the amount will generate a plain Liquid address
let optional_amount = Some(ReceiveAmount::Bitcoin {
payer_amount_sat: 5_000,
});
let prepare_response = sdk
.prepare_receive_payment(&PrepareReceiveRequest {
payment_method: PaymentMethod::LiquidAddress,
amount: optional_amount,
})
.await?;
// If the fees are acceptable, continue to create the Receive Payment
let receive_fees_sat = prepare_response.fees_sat;
info!("Fees: {} sats", receive_fees_sat);
// Create a Liquid BIP21 URI/address to receive a payment to.
// There are no limits, but the payer amount should be greater than broadcast fees when specified
// Note: Not setting the amount will generate a plain Liquid address
let optionalAmount = ReceiveAmount.bitcoin(payerAmountSat: 5_000)
let prepareResponse = try? sdk
.prepareReceivePayment(req: PrepareReceiveRequest(
paymentMethod: PaymentMethod.liquidAddress,
amount: optionalAmount
))
// If the fees are acceptable, continue to create the Receive Payment
let receiveFeesSat = prepareResponse!.feesSat;
print("Fees: {} sats", receiveFeesSat);
try {
// Create a Liquid BIP21 URI/address to receive a payment to.
// There are no limits, but the payer amount should be greater than broadcast fees when specified
// Note: Not setting the amount will generate a plain Liquid address
val optionalAmount = ReceiveAmount.Bitcoin(5_000.toULong())
val prepareRequest = PrepareReceiveRequest(PaymentMethod.LIQUID_ADDRESS, optionalAmount)
val prepareResponse = sdk.prepareReceivePayment(prepareRequest)
// If the fees are acceptable, continue to create the Receive Payment
val receiveFeesSat = prepareResponse.feesSat;
// Log.v("Breez", "Fees: ${receiveFeesSat} sats")
} catch (e: Exception) {
// handle error
}
// Create a Liquid BIP21 URI/address to receive a payment to.
// There are no limits, but the payer amount should be greater than broadcast fees when specified
// Note: Not setting the amount will generate a plain Liquid address
const optionalAmount: ReceiveAmount = {
type: ReceiveAmountVariant.BITCOIN,
payerAmountSat: 5_000
}
const prepareResponse = await prepareReceivePayment({
paymentMethod: PaymentMethod.LIQUID_ADDRESS,
amount: optionalAmount
})
// If the fees are acceptable, continue to create the Receive Payment
const receiveFeesSat = prepareResponse.feesSat
console.log(`Fees: ${receiveFeesSat} sats`)
// Create a Liquid BIP21 URI/address to receive a payment to.
// There are no limits, but the payer amount should be greater than broadcast fees when specified
// Note: Not setting the amount will generate a plain Liquid address
ReceiveAmount_Bitcoin optionalAmount = ReceiveAmount_Bitcoin(payerAmountSat: 5000 as BigInt);
PrepareReceiveResponse prepareResponse = await breezSDKLiquid.instance!.prepareReceivePayment(
req: PrepareReceiveRequest(
paymentMethod: PaymentMethod.liquidAddress,
amount: optionalAmount,
),
);
// If the fees are acceptable, continue to create the Receive Payment
BigInt receiveFeesSat = prepareResponse.feesSat;
print("Fees: $receiveFeesSat sats");
try:
# Create a Liquid BIP21 URI/address to receive a payment to.
# There are no limits, but the payer amount should be greater than broadcast fees when specified
# Note: Not setting the amount will generate a plain Liquid address
optional_amount = ReceiveAmount.BITCOIN(5_000)
prepare_request = PrepareReceiveRequest(PaymentMethod.LIQUID_ADDRESS, optional_amount)
prepare_response = sdk.prepare_receive_payment(prepare_request)
# If the fees are acceptable, continue to create the Receive Payment
receive_fees_sat = prepare_response.fees_sat
logging.debug("Fees: ", receive_fees_sat, " sats")
return prepare_response
except Exception as error:
logging.error(error)
raise
// Create a Liquid BIP21 URI/address to receive a payment to.
// There are no limits, but the payer amount should be greater than broadcast fees when specified
// Note: Not setting the amount will generate a plain Liquid address
var optionalAmount breez_sdk_liquid.ReceiveAmount = breez_sdk_liquid.ReceiveAmountBitcoin{
PayerAmountSat: uint64(5_000),
}
prepareRequest := breez_sdk_liquid.PrepareReceiveRequest{
PaymentMethod: breez_sdk_liquid.PaymentMethodLiquidAddress,
Amount: &optionalAmount,
}
if prepareResponse, err := sdk.PrepareReceivePayment(prepareRequest); err == nil {
// If the fees are acceptable, continue to create the Receive Payment
receiveFeesSat := prepareResponse.FeesSat
log.Printf("Fees: %v sats", receiveFeesSat)
}
try
{
// Create a Liquid BIP21 URI/address to receive a payment to.
// There are no limits, but the payer amount should be greater than broadcast fees when specified
// Note: Not setting the amount will generate a plain Liquid address
var optionalAmount = new ReceiveAmount.Bitcoin(5000);
var prepareRequest = new PrepareReceiveRequest(PaymentMethod.LiquidAddress, optionalAmount);
var prepareResponse = sdk.PrepareReceivePayment(prepareRequest);
// If the fees are acceptable, continue to create the Receive Payment
var receiveFeesSat = prepareResponse.feesSat;
Console.WriteLine($"Fees: {receiveFeesSat} sats");
}
catch (Exception)
{
// Handle error
}
Receiving Payments API docs
Once the payment has been prepared, all you have to do is pass the prepare response as an argument to the receive method, optionally specifying a description.
Note: The description field will be used differently, depending on the payment method:
- For Lightning payments, it will be encoded in the invoice
- For Bitcoin/Liquid BIP21 payments, it will be encoded in the URI as the
message
field. - For plain Liquid payments, the description has no effect.
let optional_description = Some("<description>".to_string());
let res = sdk
.receive_payment(&ReceivePaymentRequest {
prepare_response,
description: optional_description,
use_description_hash: None,
})
.await?;
let destination = res.destination;
let optionalDescription = "<description>"
let res = try? sdk.receivePayment(req: ReceivePaymentRequest(
prepareResponse: prepareResponse,
description: optionalDescription
))
let destination: String = res!.destination;
print("Destination: {}", destination);
try {
val optionalDescription = "<description>";
val req = ReceivePaymentRequest(prepareResponse, optionalDescription)
val res = sdk.receivePayment(req)
val destination = res.destination;
} catch (e: Exception) {
// handle error
}
const optionalDescription = '<description>'
const res = await receivePayment({
prepareResponse,
description: optionalDescription
})
const destination = res.destination
String optionalDescription = "<description>";
ReceivePaymentResponse res = await breezSDKLiquid.instance!.receivePayment(
req: ReceivePaymentRequest(
description: optionalDescription,
prepareResponse: prepareResponse,
),
);
String destination = res.destination;
try:
optional_description = "<description>"
req = ReceivePaymentRequest(prepare_response, optional_description)
res = sdk.receive_payment(req)
destination = res.destination
except Exception as error:
logging.error(error)
raise
optionalDescription := "<description>"
req := breez_sdk_liquid.ReceivePaymentRequest{
PrepareResponse: prepareResponse,
Description: &optionalDescription,
}
if res, err := sdk.ReceivePayment(req); err == nil {
// If the fees are acceptable, continue to create the Receive Payment
destination := res.Destination
log.Printf("Destination: %v", destination)
}
try
{
var optionalDescription = "<description>";
var req = new ReceivePaymentRequest(prepareResponse, optionalDescription);
var res = sdk.ReceivePayment(req);
var destination = res.destination;
}
catch (Exception)
{
// Handle error
}
Amountless Bitcoin Payments
To receive a Bitcoin payment that does not specify an amount, it may be necessary to explicitly accept the associated fees. This will be the case when the onchain fee rate increases between preparation and payment time.
Alternatively, if the fees are considered too high, the user can either choose to wait for them to come down or outright refund the payment. To learn more about refunds, see the Refunding payments section.
To reduce the likelihood of this extra fee review step being necessary, you can configure a fee rate leeway in the SDK's configuration that will automatically accept slightly higher fees within the specified tolerance.
// Payments on hold waiting for fee acceptance have the state WaitingFeeAcceptance
let payments_waiting_fee_acceptance = sdk
.list_payments(&ListPaymentsRequest {
states: Some(vec![WaitingFeeAcceptance]),
..Default::default()
})
.await?;
for payment in payments_waiting_fee_acceptance {
let PaymentDetails::Bitcoin { swap_id, .. } = payment.details else {
// Only Bitcoin payments can be `WaitingFeeAcceptance`
continue;
};
let fetch_fees_response = sdk
.fetch_payment_proposed_fees(&FetchPaymentProposedFeesRequest { swap_id })
.await?;
info!(
"Payer sent {} and currently proposed fees are {}",
fetch_fees_response.payer_amount_sat, fetch_fees_response.fees_sat
);
// If the user is ok with the fees, accept them, allowing the payment to proceed
sdk.accept_payment_proposed_fees(&AcceptPaymentProposedFeesRequest {
response: fetch_fees_response,
})
.await?;
}
// Payments on hold waiting for fee acceptance have the state WaitingFeeAcceptance
guard
let paymentsWaitingFeeAcceptance = try? sdk.listPayments(
req: ListPaymentsRequest(states: [.waitingFeeAcceptance]))
else { return }
for payment in paymentsWaitingFeeAcceptance {
guard case .bitcoin(let swapId, _, _, _, _, _, _, _) = payment.details else { continue }
// Only Bitcoin payments can be `WaitingFeeAcceptance`
guard
let fetchFeesResponse = try? sdk.fetchPaymentProposedFees(
req: FetchPaymentProposedFeesRequest(
swapId: swapId))
else { continue }
print(
"Payer sent \(fetchFeesResponse.payerAmountSat) and currently proposed fees are \(fetchFeesResponse.feesSat)"
)
// If the user is ok with the fees, accept them, allowing the payment to proceed
try? sdk.acceptPaymentProposedFees(
req: AcceptPaymentProposedFeesRequest(
response: fetchFeesResponse))
}
try {
// Payments on hold waiting for fee acceptance have the state WaitingFeeAcceptance
val paymentsWaitingFeeAcceptance = sdk.listPayments(ListPaymentsRequest(
states = listOf(PaymentState.WAITING_FEE_ACCEPTANCE)
))
for (payment in paymentsWaitingFeeAcceptance) {
when (val details = payment.details) {
is PaymentDetails.Bitcoin -> {
val fetchFeesResponse = sdk.fetchPaymentProposedFees(
FetchPaymentProposedFeesRequest(details.swapId)
)
println("Payer sent ${fetchFeesResponse.payerAmountSat} and currently proposed fees are ${fetchFeesResponse.feesSat}")
// If the user is ok with the fees, accept them, allowing the payment to proceed
sdk.acceptPaymentProposedFees(AcceptPaymentProposedFeesRequest(fetchFeesResponse))
}
else -> {
// Only Bitcoin payments can be `WaitingFeeAcceptance`
continue
}
}
}
} catch (e: Exception) {
// handle error
}
// Payments on hold waiting for fee acceptance have the state WAITING_FEE_ACCEPTANCE
const paymentsWaitingFeeAcceptance = await listPayments({
states: [PaymentState.WAITING_FEE_ACCEPTANCE]
})
for (const payment of paymentsWaitingFeeAcceptance) {
if (payment.details.type !== PaymentDetailsVariant.BITCOIN) {
// Only Bitcoin payments can be `WAITING_FEE_ACCEPTANCE`
continue
}
const fetchFeesResponse = await fetchPaymentProposedFees({
swapId: payment.details.swapId
})
console.info(
`Payer sent ${fetchFeesResponse.payerAmountSat} and currently proposed fees are ${fetchFeesResponse.feesSat}`
)
// If the user is ok with the fees, accept them, allowing the payment to proceed
await acceptPaymentProposedFees({
response: fetchFeesResponse
})
}
// Payments on hold waiting for fee acceptance have the state WaitingFeeAcceptance
List<Payment> paymentsWaitingFeeAcceptance = await breezSDKLiquid.instance!.listPayments(
req: ListPaymentsRequest(
states: [PaymentState.waitingFeeAcceptance],
),
);
for (Payment payment in paymentsWaitingFeeAcceptance) {
if (payment.details is! PaymentDetails_Bitcoin) {
// Only Bitcoin payments can be `WaitingFeeAcceptance`
continue;
}
PaymentDetails_Bitcoin details = payment.details as PaymentDetails_Bitcoin;
FetchPaymentProposedFeesResponse fetchFeesResponse =
await breezSDKLiquid.instance!.fetchPaymentProposedFees(
req: FetchPaymentProposedFeesRequest(
swapId: details.swapId,
),
);
print(
"Payer sent ${fetchFeesResponse.payerAmountSat} and currently proposed fees are ${fetchFeesResponse.feesSat}",
);
// If the user is ok with the fees, accept them, allowing the payment to proceed
await breezSDKLiquid.instance!.acceptPaymentProposedFees(
req: AcceptPaymentProposedFeesRequest(
response: fetchFeesResponse,
),
);
}
try:
# Payments on hold waiting for fee acceptance have the state WAITING_FEE_ACCEPTANCE
payments_waiting_fee_acceptance = sdk.list_payments(
ListPaymentsRequest(states=[PaymentState.WAITING_FEE_ACCEPTANCE])
)
for payment in payments_waiting_fee_acceptance:
if not isinstance(payment.details, PaymentDetails.BITCOIN):
# Only Bitcoin payments can be `WAITING_FEE_ACCEPTANCE`
continue
fetch_fees_response = sdk.fetch_payment_proposed_fees(
FetchPaymentProposedFeesRequest(payment.details.swap_id)
)
logging.info(
f"Payer sent {fetch_fees_response.payer_amount_sat} and currently proposed fees are {fetch_fees_response.fees_sat}"
)
# If the user is ok with the fees, accept them, allowing the payment to proceed
sdk.accept_payment_proposed_fees(
AcceptPaymentProposedFeesRequest(fetch_fees_response)
)
except Exception as error:
logging.error(error)
raise
// Payments on hold waiting for fee acceptance have the state WaitingFeeAcceptance
request := breez_sdk_liquid.ListPaymentsRequest{
States: &[]breez_sdk_liquid.PaymentState{breez_sdk_liquid.PaymentStateWaitingFeeAcceptance},
}
paymentsWaitingFeeAcceptance, err := sdk.ListPayments(request)
if err != nil {
return
}
for _, payment := range paymentsWaitingFeeAcceptance {
bitcoinPayment, ok := payment.Details.(breez_sdk_liquid.PaymentDetailsBitcoin)
if !ok {
// Only Bitcoin payments can be `WaitingFeeAcceptance`
continue
}
fetchFeesRequest := breez_sdk_liquid.FetchPaymentProposedFeesRequest{
SwapId: bitcoinPayment.SwapId,
}
fetchFeesResponse, err := sdk.FetchPaymentProposedFees(fetchFeesRequest)
if err != nil {
continue
}
log.Printf("Payer sent %d and currently proposed fees are %d",
fetchFeesResponse.PayerAmountSat, fetchFeesResponse.FeesSat)
// If the user is ok with the fees, accept them, allowing the payment to proceed
acceptFeesRequest := breez_sdk_liquid.AcceptPaymentProposedFeesRequest{
Response: fetchFeesResponse,
}
sdk.AcceptPaymentProposedFees(acceptFeesRequest)
}
// Payments on hold waiting for fee acceptance have the state WaitingFeeAcceptance
var paymentsWaitingFeeAcceptance = sdk.ListPayments(
new ListPaymentsRequest()
{
states = new List<PaymentState>() { PaymentState.WaitingFeeAcceptance }
});
foreach (var payment in paymentsWaitingFeeAcceptance)
{
if (payment.details is not PaymentDetails.Bitcoin bitcoinDetails)
{
// Only Bitcoin payments can be `WaitingFeeAcceptance`
continue;
}
var fetchFeesResponse = sdk.FetchPaymentProposedFees(
new FetchPaymentProposedFeesRequest(bitcoinDetails.swapId));
Console.WriteLine(
$"Payer sent {fetchFeesResponse.payerAmountSat} and currently proposed fees are {fetchFeesResponse.feesSat}");
// If the user is ok with the fees, accept them, allowing the payment to proceed
sdk.AcceptPaymentProposedFees(
new AcceptPaymentProposedFeesRequest(fetchFeesResponse));
}
Event Flows
Once a receive payment is initiated, you can follow and react to the different payment events using the guide below for each payment method. See Listening to events for how to subscribe to events.
Lightning
Event | Description | UX Suggestion |
---|---|---|
PaymentPending | The swap service is holding an incoming payment for the Lightning invoice and has broadcast a lockup transaction. The SDK has seen the lockup transaction and will broadcast the claim transaction, either when the lockup transaction is confirmed or immediately if it is accepted as a zero-conf payment. | Show payment as pending. |
PaymentWaitingConfirmation | The claim transaction has been broadcast or a direct Liquid transaction (MRH) has been seen. | Display successful payment feedback. |
PaymentSucceeded | The claim transaction or direct Liquid transaction (MRH) is confirmed. | Show payment as complete. |
PaymentFailed | The swap has failed from one of several reasons. Either the swap/invoice has expired or the lockup transaction failed to broadcast. |
Bitcoin
Event | Description | UX Suggestion |
---|---|---|
PaymentWaitingFeeAcceptance | The swap service has seen the Bitcoin lockup transaction for an amountless swap and the associated fees need to be accepted. If the fees are within the configured leeway they will be automatically accepted, otherwise the user has to explicitly accept the fees. See Amountless Bitcoin Payments. | Allow the user to review fees for this payment. |
PaymentPending | The swap service has seen the Bitcoin lockup transaction and the amount is accepted. Once the SDK has seen the Liquid lockup transaction, it will broadcast the Liquid claim transaction, either when the Liquid lockup transaction is confirmed or immediately if it is accepted as a zero-conf payment. | Show payment as pending. |
PaymentWaitingConfirmation | The Liquid claim transaction has been broadcast and is waiting confirmation. | Display successful payment feedback. |
PaymentSucceeded | The Liquid claim transaction is confirmed. | Show payment as complete. |
PaymentFailed | The swap has failed from one of several reasons. Either the swap has expired, the fee was not accepted or the Liquid lockup transaction failed to broadcast. | |
PaymentRefundable | Similar to PaymentFailed, but a Bitcoin lockup transaction was broadcast so the funds will need to be refunded, see Refunding payments. | Show payment as refundable. |
PaymentRefundPending | A Bitcoin refund transaction has been broadcast and is waiting confirmation. |
Liquid
Event | Description | UX Suggestion |
---|---|---|
PaymentWaitingConfirmation | The transaction has been seen. | Display successful payment feedback. |
PaymentSucceeded | The transaction is confirmed. | Show payment as complete. |