Parsing inputs

The SDK provides a versatile and extensible parsing module designed to process a wide range of input strings and return parsed data in various standardized formats.

Natively supported formats include: BOLT11 invoices, BOLT12 offers, LNURLs of different types, Bitcoin addresses, and others. For the complete list, consult the API documentation.

Rust
let input = "an input to be parsed...";

match sdk.parse(input).await? {
    InputType::BitcoinAddress { address } => {
        println!("Input is Bitcoin address {}", address.address);
    }
    InputType::Bolt11 { invoice } => {
        println!(
            "Input is BOLT11 invoice for {} msats",
            invoice
                .amount_msat
                .map_or("unknown".to_string(), |a| a.to_string())
        );
    }
    InputType::LnUrlPay { data } => {
        println!(
            "Input is LNURL-Pay/Lightning address accepting min/max {}/{} msats",
            data.min_sendable, data.max_sendable
        );
    }
    InputType::LnUrlWithdraw { data } => {
        println!(
            "Input is LNURL-Withdraw for min/max {}/{} msats",
            data.min_withdrawable, data.max_withdrawable
        );
    }
    // Other input types are available
    _ => {}
}
Swift
let input = "an input to be parsed..."

do {
    let inputType = try sdk.parse(input: input)
    switch inputType {
    case .bitcoinAddress(let address):
        print("Input is Bitcoin address \(address.address)")
        
    case .bolt11(let invoice):
        let amount = invoice.amountMsat.map { String($0) } ?? "unknown"
        print("Input is BOLT11 invoice for \(amount) msats")
        
    case .lnUrlPay(let data):
        print("Input is LNURL-Pay/Lightning address accepting min/max \(data.minSendable)/\(data.maxSendable) msats")
        
    case .lnUrlWithdraw(let data):
        print("Input is LNURL-Withdraw for min/max \(data.minWithdrawable)/\(data.maxWithdrawable) msats")
    
    default:
        break // Other input types are available
    }
} catch {
    print("Failed to parse input: \(error)")
}
Kotlin
val input = "an input to be parsed..."

try {
    val inputType = sdk.parse(input)
    when (inputType) {
        is InputType.BitcoinAddress -> {
            println("Input is Bitcoin address ${inputType.address.address}")
        }
        is InputType.Bolt11 -> {
            val amountStr = inputType.invoice.amountMsat?.toString() ?: "unknown"
            println("Input is BOLT11 invoice for $amountStr msats")
        }
        is InputType.LnUrlPay -> {
            println("Input is LNURL-Pay/Lightning address accepting min/max " +
                   "${inputType.data.minSendable}/${inputType.data.maxSendable} msats")
        }
        is InputType.LnUrlWithdraw -> {
            println("Input is LNURL-Withdraw for min/max " +
                   "${inputType.data.minWithdrawable}/${inputType.data.maxWithdrawable} msats")
        }
        else -> {
            // Handle other input types
        } 
    }
} catch (e: Exception) {
    // handle error
}
React Native
const input = 'an input to be parsed...'

const parsed = await parse(input)

switch (parsed.type) {
  case InputTypeVariant.BITCOIN_ADDRESS:
    console.log(`Input is Bitcoin address ${parsed.address.address}`)
    break

  case InputTypeVariant.BOLT11:
    console.log(
      `Input is BOLT11 invoice for ${
        parsed.invoice.amountMsat != null
          ? parsed.invoice.amountMsat.toString()
          : 'unknown'
      } msats`
    )
    break

  case InputTypeVariant.LN_URL_PAY:
    console.log(
      `Input is LNURL-Pay/Lightning address accepting min/max ${parsed.data.minSendable}/${parsed.data.maxSendable} msats`
    )
    break

  case InputTypeVariant.LN_URL_WITHDRAW:
    console.log(
      `Input is LNURL-Withdraw for min/max ${parsed.data.minWithdrawable}/${parsed.data.maxWithdrawable} msats`
    )
    break

  default:
    // Other input types are available
    break
}
Dart
String input = "an input to be parsed...";

InputType inputType = await breezSDKLiquid.instance!.parse(input: input);
if (inputType is InputType_BitcoinAddress) {
  print("Input is Bitcoin address ${inputType.address.address}");
} else if (inputType is InputType_Bolt11) {
  String amountStr = inputType.invoice.amountMsat != null
      ? inputType.invoice.amountMsat.toString()
      : "unknown";
  print("Input is BOLT11 invoice for $amountStr msats");
} else if (inputType is InputType_LnUrlPay) {
  print(
      "Input is LNURL-Pay/Lightning address accepting min/max ${inputType.data.minSendable}/${inputType.data.maxSendable} msats");
} else if (inputType is InputType_LnUrlWithdraw) {
  print(
      "Input is LNURL-Withdraw for min/max ${inputType.data.minWithdrawable}/${inputType.data.maxWithdrawable} msats");
} else {
  // Other input types are available
}
Python
input = "an input to be parsed..."

try:
    parsed_input = sdk.parse(input)
    if parsed_input.type == InputType.BITCOIN_ADDRESS:
        logging.debug(f"Input is Bitcoin address {parsed_input.address.address}")
    elif parsed_input.type == InputType.BOLT11:
        amount = "unknown"
        if parsed_input.invoice.amount_msat:
            amount = str(parsed_input.invoice.amount_msat)
        logging.debug(f"Input is BOLT11 invoice for {amount} msats")
    elif parsed_input.type == InputType.LN_URL_PAY:
        logging.debug(f"Input is LNURL-Pay/Lightning address accepting min/max {parsed_input.data.min_sendable}/{parsed_input.data.max_sendable} msats")
    elif parsed_input.type == InputType.LN_URL_WITHDRAW:
        logging.debug(f"Input is LNURL-Withdraw for min/max {parsed_input.data.min_withdrawable}/{parsed_input.data.max_withdrawable} msats")
    # Other input types are available
except Exception as error:
    logging.error(error)
    raise
Go
input := "an input to be parsed..."

if input, err := sdk.Parse(input); err == nil {
    switch inputType := input.(type) {
    case breez_sdk_liquid.InputTypeBitcoinAddress:
        log.Printf("Input is Bitcoin address %s", inputType.Address.Address)

    case breez_sdk_liquid.InputTypeBolt11:
        amount := "unknown"
        if inputType.Invoice.AmountMsat != nil {
            amount = strconv.FormatUint(*inputType.Invoice.AmountMsat, 10)
        }
        log.Printf("Input is BOLT11 invoice for %s msats", amount)

    case breez_sdk_liquid.InputTypeLnUrlPay:
        log.Printf("Input is LNURL-Pay/Lightning address accepting min/max %d/%d msats",
            inputType.Data.MinSendable, inputType.Data.MaxSendable)

    case breez_sdk_liquid.InputTypeLnUrlWithdraw:
        log.Printf("Input is LNURL-Withdraw for min/max %d/%d msats",
            inputType.Data.MinWithdrawable, inputType.Data.MaxWithdrawable)

    default:
        // Other input types are available
    }
}
C#
var input = "an input to be parsed...";

try
{
    var parsed = sdk.Parse(input);

    switch (parsed)
    {
        case InputType.BitcoinAddress bitcoinAddress:
            Console.WriteLine($"Input is Bitcoin address {bitcoinAddress.address}");
            break;

        case InputType.Bolt11 bolt11:
            var amount = bolt11.invoice.amountMsat.HasValue
                ? bolt11.invoice.amountMsat.Value.ToString()
                : "unknown";
            Console.WriteLine($"Input is BOLT11 invoice for {amount} msats");
            break;

        case InputType.LnUrlPay lnUrlPay:
            Console.WriteLine(
                $"Input is LNURL-Pay/Lightning address accepting min/max {lnUrlPay.data.minSendable}/{lnUrlPay.data.maxSendable} msats"
            );
            break;

        case InputType.LnUrlWithdraw lnUrlWithdraw:
            Console.WriteLine(
                $"Input is LNURL-Withdraw for min/max {lnUrlWithdraw.data.minWithdrawable}/{lnUrlWithdraw.data.maxWithdrawable} msats"
            );
            break;
        default:
            // Other input types are available
            break;
    }
}
catch (Exception)
{
    // Handle error
}

Supporting other input formats

The parsing module can be extended using external input parsers provided in the SDK configuration. These will be used when the input is not recognized.

You can implement and provide your own parsers, or use existing public ones.

Configuring external parsers

Configuring external parsers can only be done before connecting and the config cannot be changed through the lifetime of the connection.

Multiple parsers can be configured, and each one is defined by:

  • Provider ID: an arbitrary id to identify the provider input type
  • Input regex: a regex pattern that should reliably match all inputs that this parser can process, even if it may also match some invalid inputs
  • Parser URL: a URL containing the placeholder <input>

When parsing an input that isn't recognized as one of the native input types, the SDK will check if the input conforms to any of the external parsers regex expressions. If so, it will make an HTTP GET request to the provided URL, replacing the placeholder with the input. If the input is recognized, the response should include in its body a string that can be parsed into one of the natively supported types.

Rust
let mnemonic = Mnemonic::generate_in(Language::English, 12)?;

// Create the default config, providing your Breez API key
let mut config = LiquidSdk::default_config(
    LiquidNetwork::Mainnet,
    Some("<your-Breez-API-key>".to_string()),
)?;

// Configure external parsers
config.external_input_parsers = Some(vec![
    ExternalInputParser {
        provider_id: "provider_a".to_string(),
        input_regex: "^provider_a".to_string(),
        parser_url: "https://parser-domain.com/parser?input=<input>".to_string(),
    },
    ExternalInputParser {
        provider_id: "provider_b".to_string(),
        input_regex: "^provider_b".to_string(),
        parser_url: "https://parser-domain.com/parser?input=<input>".to_string(),
    },
]);

let connect_request = ConnectRequest {
    mnemonic: mnemonic.to_string(),
    config,
};
let sdk = LiquidSdk::connect(connect_request).await?;
Swift
let mnemonic = "<mnemonic words>"

// Create the default config, providing your Breez API key
var config = try defaultConfig(network: LiquidNetwork.mainnet, breezApiKey: "<your-Breez-API-key>")

// Configure external parsers
config.externalInputParsers = [
    ExternalInputParser(
        providerId: "provider_a",
        inputRegex: "^provider_a",
        parserUrl: "https://parser-domain.com/parser?input=<input>"
    ),
    ExternalInputParser(
        providerId: "provider_b", 
        inputRegex: "^provider_b",
        parserUrl: "https://parser-domain.com/parser?input=<input>"
    )
]

let connectRequest = ConnectRequest(config: config, mnemonic: mnemonic)
let sdk = try? connect(req: connectRequest)
Kotlin
val mnemonic = "<mnemonic words>"

// Create the default config, providing your Breez API key
val config : Config = defaultConfig(LiquidNetwork.MAINNET, "<your Breez API key>")

// Configure external parsers
config.externalInputParsers = listOf(
    ExternalInputParser(
        providerId = "provider_a",
        inputRegex = "^provider_a",
        parserUrl = "https://parser-domain.com/parser?input=<input>"
    ),
    ExternalInputParser(
        providerId = "provider_b", 
        inputRegex = "^provider_b",
        parserUrl = "https://parser-domain.com/parser?input=<input>"
    )
)

try {
    val connectRequest = ConnectRequest(config, mnemonic)
    val sdk = connect(connectRequest)
} catch (e: Exception) {
    // handle error
}
React Native
const mnemonic = '<mnemonics words>'

// Create the default config, providing your Breez API key
const config = await defaultConfig(
  LiquidNetwork.MAINNET,
  '<your-Breez-API-key>'
)

// Configure external parsers
config.externalInputParsers = [
  {
    providerId: 'provider_a',
    inputRegex: '^provider_a',
    parserUrl: 'https://parser-domain.com/parser?input=<input>'
  },
  {
    providerId: 'provider_b',
    inputRegex: '^provider_b',
    parserUrl: 'https://parser-domain.com/parser?input=<input>'
  }
]

await connect({ mnemonic, config })
Dart
// Create the default config
String mnemonic = "<mnemonic words>";

// Create the default config, providing your Breez API key
Config config = defaultConfig(
  network: LiquidNetwork.mainnet,
  breezApiKey: "<your-Breez-API-key>"
);

// Configure external parsers
config = config.copyWith(
  externalInputParsers: [
    ExternalInputParser(
      providerId: "provider_a",
      inputRegex: "^provider_a",
      parserUrl: "https://parser-domain.com/parser?input=<input>",
    ),
    ExternalInputParser(
      providerId: "provider_b", 
      inputRegex: "^provider_b",
      parserUrl: "https://parser-domain.com/parser?input=<input>",
    ),
  ],
);

ConnectRequest connectRequest = ConnectRequest(mnemonic: mnemonic, config: config);

await breezSDKLiquid.connect(req: connectRequest);

Python
mnemonic = "<mnemonic words>"

# Create the default config, providing your Breez API key
config = default_config(network=LiquidNetwork.MAINNET, breez_api_key="<your-Breez-API-key>")

# Configure external parsers
config.external_input_parsers = [
    ExternalInputParser(
        provider_id="provider_a",
        input_regex="^provider_a",
        parser_url="https://parser-domain.com/parser?input=<input>"
    ),
    ExternalInputParser(
        provider_id="provider_b",
        input_regex="^provider_b",
        parser_url="https://parser-domain.com/parser?input=<input>"
    )
]

try:
    connect_request = ConnectRequest(config, mnemonic)
    sdk = connect(connect_request)
    return sdk
except Exception as error:
    logging.error(error)
    raise
Go
mnemonic := "<mnemonic words>"

// Create the default config, providing your Breez API key
breezApiKey := "<your-Breez-API-key>"
config, err := breez_sdk_liquid.DefaultConfig(breez_sdk_liquid.LiquidNetworkMainnet, &breezApiKey)
if err != nil {
    return nil, err
}

// Configure external parsers
parsers := []breez_sdk_liquid.ExternalInputParser{
    {
        ProviderId: "provider_a",
        InputRegex: "^provider_a",
        ParserUrl:  "https://parser-domain.com/parser?input=<input>",
    },
    {
        ProviderId: "provider_b",
        InputRegex: "^provider_b",
        ParserUrl:  "https://parser-domain.com/parser?input=<input>",
    },
}
config.ExternalInputParsers = &parsers

connectRequest := breez_sdk_liquid.ConnectRequest{
    Config:   config,
    Mnemonic: mnemonic,
}

sdk, err := breez_sdk_liquid.Connect(connectRequest)

return sdk, err
C#
var mnemonic = "<mnemonic words>";

// Create the default config, providing your Breez API key
var config = BreezSdkLiquidMethods.DefaultConfig(
    LiquidNetwork.Mainnet,
    "<your-Breez-API-key>"
) with
{
    // Configure external parsers
    externalInputParsers = new List<ExternalInputParser>
    {
        new(
            providerId: "provider_a",
            inputRegex: "^provider_a",
            parserUrl: "https://parser-domain.com/parser?input=<input>"
        ),
        new(
            providerId: "provider_b", 
            inputRegex: "^provider_b",
            parserUrl: "https://parser-domain.com/parser?input=<input>"
        )
    }
};

try
{
    var connectRequest = new ConnectRequest(config, mnemonic);
    var sdk = BreezSdkLiquidMethods.Connect(connectRequest);
}
catch (Exception)
{
    // Handle error
}

Public external parsers

  • PicknPay QRs
    • Maintainer: MoneyBadger
    • Regex: (.*)(za.co.electrum.picknpay)(.*)
    • URL: https://staging.cryptoqr.net/.well-known/lnurlp/<input>

Default external parsers

The SDK ships with some embedded default external parsers. If you prefer not to use them, you can disable them in the SDK's configuration. See the available default parsers in the API Documentation by checking the source of the constant.