Repository: breez/breez-sdk-liquid (language: python)

Issue:
Add external plugins to our input parser 
There are legacy POS systems where partners have no control or ability to change their QRs. 
The idea here is to allow an SDK user to register external parser URLs that return valid lnurlp/bolt11 in response to a given string. 
One example is here: https://docs.google.com/document/d/1g_DAmaQY66uo1oXJNQutMnVw_sQjDhjJoeme2LOXets/edit?usp=sharing

We want our partners to be able to register https://staging.cryptoqr.net/.well-known/lnurlp/ and an external input parser. Input strings passed to the plugin should be url encoded. 


Discussion / hints:
@kingonly Should we support the specific implementation by Moneybadger? IMO it's too specific. It entails a Lightning address-style lookup but is not compliant because it skips the 2nd request in LNURL-pay. 

We could keep our implementation generic by requiring partners to provide an input parser server that returns any format we support in the SDK (as would usually be provided to `parse()`). This would make it easier for others to use this feature and allow resolving to types other than bolt11.

The downside is that it requires the currently interested partner (MoneyBadger) to implement an additional endpoint.
From a business standpoint, yes. We need to support MoneyBadger. 

Not sure I understand the problem. The parse return a valid lnurl-pay URL: https://breez-tech.slack.com/archives/C07SLM3H7D2/p1729678850977259
Indeed, it does. The Google doc isn't up to date. Thanks
@danielgranhao I think you are right about trying to give here a generic solution as long as it is not adding too much of a complexity.
I was thinking about letting the user define a list of input handler configurations that each of them takes:
* regex to qualify the input
* URL with a place holder (for the input)  to invoke as an external endpoint which resolves the lnurlpay or anything our input 
parser supports (can actually be arbitrary input: bolt11, offer etc..)
* We can also add name of the external provider

We can use these handlers on unidentified input untill one of them resolves.
What do you think?
@roeierez I like it. But again, that means MoneyBadger would need to implement a compatible parser. If that's acceptable, I'll proceed with a proposal for the implementation.
Right! As far as I understand they have that endpoint implemented and the SDK responsibility is only to invoke that external URL (parser).
They provide a LightningAddress/LNURL-pay server. The response to a request to their endpoint is something like: 
```
{"callback":"<callback_url>","minSendable":57000,"maxSendable":57000,"metadata":"[[\"text/plain\", \"Pick n Pay Payment\"]]","tag":"payRequest"}
```
This isn't something we can work with directly using the SDK's parser. We would need to make a 2nd request to the callback to get something useful (the payment request).

This can work, of course, but it doesn't make for a generic solution.
I don't understand. All we need to do is to add a regex to parse the response from the parser. This can be done generically. Meaning the engine is generic, the configuration is specific. 

We can the parser url with the QR data (configuration), we parse the response to get the lnurlp end point and from there it's just our regular flow. What am I missing? 

https://docs.google.com/document/d/1g_DAmaQY66uo1oXJNQutMnVw_sQjDhjJoeme2LOXets/edit?usp=drivesdk
@roeierez and I continued the discussion out-of-band, and I'm now working on a solution that doesn't require any changes from MoneyBadger's side. 

The point was that Moneybadger's parser doesn't return an lnurlp endpoint. The parser **is** the lnurlp endpoint itself.
I'm nonetheless working on a solution that should work anyway.  
Nope, the parser isn't the lnurlp endpoint. That's the reason their service exists. It's to convert legacy POS QRs to lnurlp. See the document and the discussion in the MoneyBadger channel. 
@kingonly I thought the same but it turns out the end point combined with the input data is the url for lnurl pay. Invoking this url returns the first response of lnurl protocol and not the lnurl itself.
We can handle that by returning this constructed url as the lnurl pay to the user which meets our use case requirements
All good. 

Fix patch:
diff --git a/cli/Cargo.lock b/cli/Cargo.lock
index 27600a26..aa3018e9 100644
--- a/cli/Cargo.lock
+++ b/cli/Cargo.lock
@@ -2672,9 +2672,9 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.10.6"
+version = "1.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -2684,9 +2684,9 @@ dependencies = [
 
 [[package]]
 name = "regex-automata"
-version = "0.4.7"
+version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -2701,9 +2701,9 @@ checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a"
 
 [[package]]
 name = "regex-syntax"
-version = "0.8.4"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
 
 [[package]]
 name = "reqwest"
@@ -3046,7 +3046,7 @@ dependencies = [
 [[package]]
 name = "sdk-common"
 version = "0.6.2"
-source = "git+https://github.com/breez/breez-sdk?rev=5955216ec4ed003972b4473a77207dfb744da882#5955216ec4ed003972b4473a77207dfb744da882"
+source = "git+https://github.com/breez/breez-sdk?rev=238245bd34be15727493d7d0c625c6ae55f2a845#238245bd34be15727493d7d0c625c6ae55f2a845"
 dependencies = [
  "aes 0.8.4",
  "anyhow",
@@ -3059,6 +3059,7 @@ dependencies = [
  "lightning 0.0.118",
  "lightning-invoice 0.26.0",
  "log",
+ "percent-encoding",
  "prost",
  "querystring",
  "regex",
@@ -3112,7 +3113,7 @@ version = "0.29.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113"
 dependencies = [
- "bitcoin_hashes 0.13.0",
+ "bitcoin_hashes 0.14.0",
  "secp256k1-sys 0.10.1",
 ]
 
@@ -3577,9 +3578,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 
 [[package]]
 name = "tokio"
-version = "1.39.3"
+version = "1.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9babc99b9923bfa4804bd74722ff02c0381021eafa4db9949217e3be8e84fff5"
+checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551"
 dependencies = [
  "backtrace",
  "bytes",
diff --git a/cli/src/commands.rs b/cli/src/commands.rs
index 89ebd86c..1101724b 100644
--- a/cli/src/commands.rs
+++ b/cli/src/commands.rs
@@ -298,7 +298,7 @@ pub(crate) async fn handle_command(
             let mut result = command_result!(&response);
             result.push('\n');
 
-            match parse(&response.destination).await? {
+            match parse(&response.destination, None).await? {
                 InputType::Bolt11 { invoice } => result.push_str(&build_qr_text(&invoice.bolt11)),
                 InputType::LiquidAddress { address } => {
                     result.push_str(&build_qr_text(&address.to_uri().map_err(|e| {
@@ -574,14 +574,14 @@ pub(crate) async fn handle_command(
             command_result!("Liquid SDK instance disconnected")
         }
         Command::Parse { input } => {
-            let res = LiquidSdk::parse(&input).await?;
+            let res = sdk.parse(&input).await?;
             command_result!(res)
         }
         Command::LnurlPay {
             lnurl,
             validate_success_url,
         } => {
-            let input = LiquidSdk::parse(&lnurl).await?;
+            let input = sdk.parse(&lnurl).await?;
             let res = match input {
                 InputType::LnUrlPay { data: pd } => {
                     let prompt = format!(
@@ -618,7 +618,7 @@ pub(crate) async fn handle_command(
             command_result!(res)
         }
         Command::LnurlWithdraw { lnurl } => {
-            let input = LiquidSdk::parse(&lnurl).await?;
+            let input = sdk.parse(&lnurl).await?;
             let res = match input {
                 InputType::LnUrlWithdraw { data: pd } => {
                     let prompt = format!(
@@ -644,7 +644,7 @@ pub(crate) async fn handle_command(
         Command::LnurlAuth { lnurl } => {
             let lnurl_endpoint = lnurl.trim();
 
-            let res = match parse(lnurl_endpoint).await? {
+            let res = match parse(lnurl_endpoint, None).await? {
                 InputType::LnUrlAuth { data: ad } => {
                     let auth_res = sdk.lnurl_auth(ad).await?;
                     serde_json::to_string_pretty(&auth_res).map_err(|e| e.into())
diff --git a/lib/Cargo.lock b/lib/Cargo.lock
index cca4156d..2029f697 100644
--- a/lib/Cargo.lock
+++ b/lib/Cargo.lock
@@ -2429,9 +2429,9 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.19.0"
+version = "1.20.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3fdb12b2476b595f9358c5161aa467c2438859caa136dec86c26fdd2efe17b92"
+checksum = "1261fe7e33c73b354eab43b1273a57c8f967d0391e80353e51f764ac02cf6775"
 
 [[package]]
 name = "oneshot-uniffi"
@@ -2925,9 +2925,9 @@ dependencies = [
 
 [[package]]
 name = "regex"
-version = "1.10.6"
+version = "1.11.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4219d74c6b67a3654a9fbebc4b419e22126d13d2f3c4a07ee0cb61ff79a79619"
+checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -2937,9 +2937,9 @@ dependencies = [
 
 [[package]]
 name = "regex-automata"
-version = "0.4.7"
+version = "0.4.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "38caf58cc5ef2fed281f89292ef23f6365465ed9a41b7a7754eb4e26496c92df"
+checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
 dependencies = [
  "aho-corasick",
  "memchr",
@@ -2954,9 +2954,9 @@ checksum = "53a49587ad06b26609c52e423de037e7f57f20d53535d66e08c695f347df952a"
 
 [[package]]
 name = "regex-syntax"
-version = "0.8.4"
+version = "0.8.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7a66a03ae7c801facd77a29370b4faec201768915ac14a721ba36f20bc9c209b"
+checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
 
 [[package]]
 name = "remove_dir_all"
@@ -3294,7 +3294,7 @@ dependencies = [
 [[package]]
 name = "sdk-common"
 version = "0.6.2"
-source = "git+https://github.com/breez/breez-sdk?rev=5955216ec4ed003972b4473a77207dfb744da882#5955216ec4ed003972b4473a77207dfb744da882"
+source = "git+https://github.com/breez/breez-sdk?rev=e537feb8ed134bc3c7af5196e10a0a189dd36ac7#e537feb8ed134bc3c7af5196e10a0a189dd36ac7"
 dependencies = [
  "aes 0.8.4",
  "anyhow",
@@ -3307,6 +3307,7 @@ dependencies = [
  "lightning 0.0.118",
  "lightning-invoice 0.26.0",
  "log",
+ "percent-encoding",
  "prost",
  "querystring",
  "regex",
@@ -3360,7 +3361,7 @@ version = "0.29.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9465315bc9d4566e1724f0fffcbcc446268cb522e60f9a27bcded6b19c108113"
 dependencies = [
- "bitcoin_hashes 0.13.0",
+ "bitcoin_hashes 0.14.0",
  "secp256k1-sys 0.10.1",
 ]
 
@@ -3862,9 +3863,9 @@ checksum = "1f3ccbac311fea05f86f61904b462b55fb3df8837a366dfc601a0161d0532f20"
 
 [[package]]
 name = "tokio"
-version = "1.40.0"
+version = "1.42.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "e2b070231665d27ad9ec9b8df639893f46727666c6767db40317fbe920a5d998"
+checksum = "5cec9b21b0450273377fc97bd4c33a8acffc8c996c987a7c5b319a0083707551"
 dependencies = [
  "backtrace",
  "bytes",
diff --git a/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h b/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h
index c22c6c18..0ed007dd 100644
--- a/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h
+++ b/lib/bindings/langs/flutter/breez_sdk_liquid/include/breez_sdk_liquid.h
@@ -489,6 +489,11 @@ typedef struct wire_cst_sdk_event {
   union SdkEventKind kind;
 } wire_cst_sdk_event;
 
+typedef struct wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser {
+  uintptr_t *ptr;
+  int32_t len;
+} wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser;
+
 typedef struct wire_cst_config {
   struct wire_cst_list_prim_u_8_strict *liquid_electrum_url;
   struct wire_cst_list_prim_u_8_strict *bitcoin_electrum_url;
@@ -500,6 +505,7 @@ typedef struct wire_cst_config {
   uint32_t zero_conf_min_fee_rate_msat;
   uint64_t *zero_conf_max_amount_sat;
   struct wire_cst_list_prim_u_8_strict *breez_api_key;
+  struct wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser *external_input_parsers;
 } wire_cst_config;
 
 typedef struct wire_cst_connect_request {
@@ -1091,6 +1097,10 @@ void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_lnurl_withdraw(
                                                                                 uintptr_t that,
                                                                                 struct wire_cst_ln_url_withdraw_request *req);
 
+void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_parse(int64_t port_,
+                                                                       uintptr_t that,
+                                                                       struct wire_cst_list_prim_u_8_strict *input);
+
 void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_pay_onchain(int64_t port_,
                                                                              uintptr_t that,
                                                                              struct wire_cst_pay_onchain_request *req);
@@ -1166,15 +1176,16 @@ void frbgen_breez_liquid_wire__crate__bindings__connect(int64_t port_,
 WireSyncRust2DartDco frbgen_breez_liquid_wire__crate__bindings__default_config(int32_t network,
                                                                                struct wire_cst_list_prim_u_8_strict *breez_api_key);
 
-void frbgen_breez_liquid_wire__crate__bindings__parse(int64_t port_,
-                                                      struct wire_cst_list_prim_u_8_strict *input);
-
 WireSyncRust2DartDco frbgen_breez_liquid_wire__crate__bindings__parse_invoice(struct wire_cst_list_prim_u_8_strict *input);
 
 void frbgen_breez_liquid_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(const void *ptr);
 
 void frbgen_breez_liquid_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(const void *ptr);
 
+void frbgen_breez_liquid_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(const void *ptr);
+
+void frbgen_breez_liquid_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(const void *ptr);
+
 struct wire_cst_aes_success_action_data *frbgen_breez_liquid_cst_new_box_autoadd_aes_success_action_data(void);
 
 struct wire_cst_aes_success_action_data_decrypted *frbgen_breez_liquid_cst_new_box_autoadd_aes_success_action_data_decrypted(void);
@@ -1275,6 +1286,8 @@ uint64_t *frbgen_breez_liquid_cst_new_box_autoadd_u_64(uint64_t value);
 
 struct wire_cst_url_success_action_data *frbgen_breez_liquid_cst_new_box_autoadd_url_success_action_data(void);
 
+struct wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser *frbgen_breez_liquid_cst_new_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(int32_t len);
+
 struct wire_cst_list_String *frbgen_breez_liquid_cst_new_list_String(int32_t len);
 
 struct wire_cst_list_fiat_currency *frbgen_breez_liquid_cst_new_list_fiat_currency(int32_t len);
@@ -1350,6 +1363,7 @@ static int64_t dummy_method_to_enforce_bundling(void) {
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_u_32);
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_u_64);
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_box_autoadd_url_success_action_data);
+    dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser);
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_list_String);
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_list_fiat_currency);
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_list_ln_offer_blinded_path);
@@ -1363,7 +1377,9 @@ static int64_t dummy_method_to_enforce_bundling(void) {
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_list_route_hint);
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_cst_new_list_route_hint_hop);
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk);
+    dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser);
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk);
+    dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser);
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_add_event_listener);
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_backup);
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_buy_bitcoin);
@@ -1381,6 +1397,7 @@ static int64_t dummy_method_to_enforce_bundling(void) {
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_lnurl_auth);
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_lnurl_pay);
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_lnurl_withdraw);
+    dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_parse);
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_pay_onchain);
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_buy_bitcoin);
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_prepare_lnurl_pay);
@@ -1402,7 +1419,6 @@ static int64_t dummy_method_to_enforce_bundling(void) {
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__breez_log_stream);
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__connect);
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__default_config);
-    dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__parse);
     dummy_var ^= ((int64_t) (void*) frbgen_breez_liquid_wire__crate__bindings__parse_invoice);
     dummy_var ^= ((int64_t) (void*) store_dart_post_cobject);
     return dummy_var;
diff --git a/lib/bindings/src/breez_sdk_liquid.udl b/lib/bindings/src/breez_sdk_liquid.udl
index d1975ceb..a06e7ee6 100644
--- a/lib/bindings/src/breez_sdk_liquid.udl
+++ b/lib/bindings/src/breez_sdk_liquid.udl
@@ -335,6 +335,7 @@ dictionary Config {
     string? breez_api_key;
     string? cache_dir;
     u64? zero_conf_max_amount_sat;
+    sequence<ExternalInputParser>? external_input_parsers = null;
 };
 
 enum LiquidNetwork {
@@ -629,6 +630,12 @@ dictionary LogEntry {
     string level;
 };
 
+dictionary ExternalInputParser {
+    string provider_id;
+    string input_regex;
+    string parser_url;
+};
+
 namespace breez_sdk_liquid {
     [Throws=SdkError]
     BindingLiquidSdk connect(ConnectRequest req);
@@ -642,9 +649,6 @@ namespace breez_sdk_liquid {
     [Throws=SdkError]
     Config default_config(LiquidNetwork network, string? breez_api_key);
 
-    [Throws=PaymentError]
-    InputType parse(string input);
-
     [Throws=PaymentError]
     LNInvoice parse_invoice(string input);
 };
@@ -690,6 +694,9 @@ interface BindingLiquidSdk {
     [Throws=SdkError]
     CheckMessageResponse check_message(CheckMessageRequest req);
 
+    [Throws=PaymentError]
+    InputType parse(string input);
+
     [Throws=PaymentError]
     PrepareSendResponse prepare_send_payment(PrepareSendRequest req);
 
diff --git a/lib/bindings/src/lib.rs b/lib/bindings/src/lib.rs
index 11223041..d3db7039 100644
--- a/lib/bindings/src/lib.rs
+++ b/lib/bindings/src/lib.rs
@@ -71,9 +71,6 @@ pub fn default_config(
     LiquidSdk::default_config(network, breez_api_key)
 }
 
-pub fn parse(input: String) -> Result<InputType, PaymentError> {
-    rt().block_on(async { LiquidSdk::parse(&input).await })
-}
 pub fn parse_invoice(input: String) -> Result<LNInvoice, PaymentError> {
     LiquidSdk::parse_invoice(&input)
 }
@@ -103,6 +100,10 @@ impl BindingLiquidSdk {
         self.sdk.check_message(&req)
     }
 
+    pub fn parse(&self, input: String) -> Result<InputType, PaymentError> {
+        rt().block_on(async { self.sdk.parse(&input).await })
+    }
+
     pub fn prepare_send_payment(
         &self,
         req: PrepareSendRequest,
diff --git a/lib/core/Cargo.toml b/lib/core/Cargo.toml
index 2a8b4b6c..9c1e1c13 100644
--- a/lib/core/Cargo.toml
+++ b/lib/core/Cargo.toml
@@ -21,7 +21,7 @@ boltz-client = { git = "https://github.com/SatoshiPortal/boltz-rust", branch = "
 chrono = "0.4"
 env_logger = "0.11"
 flutter_rust_bridge = { version = "=2.4.0", features = [
-  "chrono",
+    "chrono",
 ], optional = true }
 # We need at least lightning v0.0.125 for the Bolt12 structs. The lightning version from sdk-common is too old (v0.0.118, matching vls-core).
 lightning = "0.0.125"
@@ -32,7 +32,7 @@ lwk_wollet = { git = "https://github.com/dangeross/lwk", branch = "savage-full-s
 #lwk_wollet = "0.7.0"
 rusqlite = { version = "0.31", features = ["backup", "bundled"] }
 rusqlite_migration = "1.0"
-sdk-common = { git = "https://github.com/breez/breez-sdk", rev = "5955216ec4ed003972b4473a77207dfb744da882", features = ["liquid"]}
+sdk-common = { git = "https://github.com/breez/breez-sdk", rev = "e537feb8ed134bc3c7af5196e10a0a189dd36ac7", features = ["liquid"] }
 serde = { version = "1.0.197", features = ["derive"] }
 serde_json = "1.0.116"
 strum = "0.25"
@@ -44,8 +44,8 @@ tokio = { version = "1", features = ["rt", "macros"] }
 tokio-stream = { version = "0.1.14", features = ["sync"] }
 url = "2.5.0"
 futures-util = { version = "0.3.28", default-features = false, features = [
-  "sink",
-  "std",
+    "sink",
+    "std",
 ] }
 async-trait = "0.1.80"
 hex = "0.4"
diff --git a/lib/core/src/bindings.rs b/lib/core/src/bindings.rs
index f5780182..15346736 100644
--- a/lib/core/src/bindings.rs
+++ b/lib/core/src/bindings.rs
@@ -66,10 +66,6 @@ pub fn default_config(
     LiquidSdk::default_config(network, breez_api_key)
 }
 
-pub async fn parse(input: String) -> Result<InputType, PaymentError> {
-    LiquidSdk::parse(&input).await
-}
-
 #[frb(sync)]
 pub fn parse_invoice(input: String) -> Result<LNInvoice, PaymentError> {
     LiquidSdk::parse_invoice(&input)
@@ -97,6 +93,10 @@ impl BindingLiquidSdk {
         self.sdk.check_message(&req)
     }
 
+    pub async fn parse(&self, input: String) -> Result<InputType, PaymentError> {
+        self.sdk.parse(&input).await
+    }
+
     pub async fn add_event_listener(
         &self,
         listener: StreamSink<SdkEvent>,
diff --git a/lib/core/src/frb_generated.rs b/lib/core/src/frb_generated.rs
index 289c9174..b00ad46b 100644
--- a/lib/core/src/frb_generated.rs
+++ b/lib/core/src/frb_generated.rs
@@ -27,6 +27,7 @@
 
 use crate::bindings::*;
 use crate::model::EventListener;
+use crate::*;
 use flutter_rust_bridge::for_generated::byteorder::{NativeEndian, ReadBytesExt, WriteBytesExt};
 use flutter_rust_bridge::for_generated::{transform_result_dco, Lifetimeable, Lockable};
 use flutter_rust_bridge::{Handler, IntoIntoDart};
@@ -39,7 +40,7 @@ flutter_rust_bridge::frb_generated_boilerplate!(
     default_rust_auto_opaque = RustAutoOpaqueNom,
 );
 pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_VERSION: &str = "2.4.0";
-pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = 425220482;
+pub(crate) const FLUTTER_RUST_BRIDGE_CODEGEN_CONTENT_HASH: i32 = -2032324171;
 
 // Section: executor
 
@@ -815,6 +816,53 @@ fn wire__crate__bindings__BindingLiquidSdk_lnurl_withdraw_impl(
         },
     )
 }
+fn wire__crate__bindings__BindingLiquidSdk_parse_impl(
+    port_: flutter_rust_bridge::for_generated::MessagePort,
+    that: impl CstDecode<
+        RustOpaqueNom<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<BindingLiquidSdk>>,
+    >,
+    input: impl CstDecode<String>,
+) {
+    FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::<flutter_rust_bridge::for_generated::DcoCodec, _, _, _>(
+        flutter_rust_bridge::for_generated::TaskInfo {
+            debug_name: "BindingLiquidSdk_parse",
+            port: Some(port_),
+            mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
+        },
+        move || {
+            let api_that = that.cst_decode();
+            let api_input = input.cst_decode();
+            move |context| async move {
+                transform_result_dco::<_, _, crate::error::PaymentError>(
+                    (move || async move {
+                        let mut api_that_guard = None;
+                        let decode_indices_ =
+                            flutter_rust_bridge::for_generated::lockable_compute_decode_order(
+                                vec![flutter_rust_bridge::for_generated::LockableOrderInfo::new(
+                                    &api_that, 0, false,
+                                )],
+                            );
+                        for i in decode_indices_ {
+                            match i {
+                                0 => {
+                                    api_that_guard =
+                                        Some(api_that.lockable_decode_async_ref().await)
+                                }
+                                _ => unreachable!(),
+                            }
+                        }
+                        let api_that_guard = api_that_guard.unwrap();
+                        let output_ok =
+                            crate::bindings::BindingLiquidSdk::parse(&*api_that_guard, api_input)
+                                .await?;
+                        Ok(output_ok)
+                    })()
+                    .await,
+                )
+            }
+        },
+    )
+}
 fn wire__crate__bindings__BindingLiquidSdk_pay_onchain_impl(
     port_: flutter_rust_bridge::for_generated::MessagePort,
     that: impl CstDecode<
@@ -1698,30 +1746,6 @@ fn wire__crate__bindings__default_config_impl(
         },
     )
 }
-fn wire__crate__bindings__parse_impl(
-    port_: flutter_rust_bridge::for_generated::MessagePort,
-    input: impl CstDecode<String>,
-) {
-    FLUTTER_RUST_BRIDGE_HANDLER.wrap_async::<flutter_rust_bridge::for_generated::DcoCodec, _, _, _>(
-        flutter_rust_bridge::for_generated::TaskInfo {
-            debug_name: "parse",
-            port: Some(port_),
-            mode: flutter_rust_bridge::for_generated::FfiCallMode::Normal,
-        },
-        move || {
-            let api_input = input.cst_decode();
-            move |context| async move {
-                transform_result_dco::<_, _, crate::error::PaymentError>(
-                    (move || async move {
-                        let output_ok = crate::bindings::parse(api_input).await?;
-                        Ok(output_ok)
-                    })()
-                    .await,
-                )
-            }
-        },
-    )
-}
 fn wire__crate__bindings__parse_invoice_impl(
     input: impl CstDecode<String>,
 ) -> flutter_rust_bridge::for_generated::WireSyncRust2DartDco {
@@ -2125,6 +2149,16 @@ impl SseDecode for BindingLiquidSdk {
     }
 }
 
+impl SseDecode for ExternalInputParser {
+    // Codec=Sse (Serialization based), see doc to use other codecs
+    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
+        let mut inner = <RustOpaqueNom<
+            flutter_rust_bridge::for_generated::RustAutoOpaqueInner<ExternalInputParser>,
+        >>::sse_decode(deserializer);
+        return flutter_rust_bridge::for_generated::rust_auto_opaque_decode_owned(inner);
+    }
+}
+
 impl SseDecode
     for RustOpaqueNom<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<BindingLiquidSdk>>
 {
@@ -2135,6 +2169,16 @@ impl SseDecode
     }
 }
 
+impl SseDecode
+    for RustOpaqueNom<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<ExternalInputParser>>
+{
+    // Codec=Sse (Serialization based), see doc to use other codecs
+    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
+        let mut inner = <usize>::sse_decode(deserializer);
+        return unsafe { decode_rust_opaque_nom(inner) };
+    }
+}
+
 impl SseDecode
     for StreamSink<crate::model::LogEntry, flutter_rust_bridge::for_generated::DcoCodec>
 {
@@ -2345,6 +2389,8 @@ impl SseDecode for crate::model::Config {
         let mut var_zeroConfMinFeeRateMsat = <u32>::sse_decode(deserializer);
         let mut var_zeroConfMaxAmountSat = <Option<u64>>::sse_decode(deserializer);
         let mut var_breezApiKey = <Option<String>>::sse_decode(deserializer);
+        let mut var_externalInputParsers =
+            <Option<Vec<ExternalInputParser>>>::sse_decode(deserializer);
         return crate::model::Config {
             liquid_electrum_url: var_liquidElectrumUrl,
             bitcoin_electrum_url: var_bitcoinElectrumUrl,
@@ -2356,6 +2402,7 @@ impl SseDecode for crate::model::Config {
             zero_conf_min_fee_rate_msat: var_zeroConfMinFeeRateMsat,
             zero_conf_max_amount_sat: var_zeroConfMaxAmountSat,
             breez_api_key: var_breezApiKey,
+            external_input_parsers: var_externalInputParsers,
         };
     }
 }
@@ -2586,6 +2633,18 @@ impl SseDecode for crate::model::LiquidNetwork {
     }
 }
 
+impl SseDecode for Vec<ExternalInputParser> {
+    // Codec=Sse (Serialization based), see doc to use other codecs
+    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
+        let mut len_ = <i32>::sse_decode(deserializer);
+        let mut ans_ = vec![];
+        for idx_ in 0..len_ {
+            ans_.push(<ExternalInputParser>::sse_decode(deserializer));
+        }
+        return ans_;
+    }
+}
+
 impl SseDecode for Vec<String> {
     // Codec=Sse (Serialization based), see doc to use other codecs
     fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
@@ -3403,6 +3462,17 @@ impl SseDecode for Option<u64> {
     }
 }
 
+impl SseDecode for Option<Vec<ExternalInputParser>> {
+    // Codec=Sse (Serialization based), see doc to use other codecs
+    fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
+        if (<bool>::sse_decode(deserializer)) {
+            return Some(<Vec<ExternalInputParser>>::sse_decode(deserializer));
+        } else {
+            return None;
+        }
+    }
+}
+
 impl SseDecode for Option<Vec<crate::model::PaymentType>> {
     // Codec=Sse (Serialization based), see doc to use other codecs
     fn sse_decode(deserializer: &mut flutter_rust_bridge::for_generated::SseDeserializer) -> Self {
@@ -4273,6 +4343,24 @@ impl flutter_rust_bridge::IntoIntoDart<FrbWrapper<BindingLiquidSdk>> for Binding
     }
 }
 
+// Codec=Dco (DartCObject based), see doc to use other codecs
+impl flutter_rust_bridge::IntoDart for FrbWrapper<ExternalInputParser> {
+    fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
+        flutter_rust_bridge::for_generated::rust_auto_opaque_encode::<_, StdArc<_>>(self.0)
+            .into_dart()
+    }
+}
+impl flutter_rust_bridge::for_generated::IntoDartExceptPrimitive
+    for FrbWrapper<ExternalInputParser>
+{
+}
+
+impl flutter_rust_bridge::IntoIntoDart<FrbWrapper<ExternalInputParser>> for ExternalInputParser {
+    fn into_into_dart(self) -> FrbWrapper<ExternalInputParser> {
+        self.into()
+    }
+}
+
 // Codec=Dco (DartCObject based), see doc to use other codecs
 impl flutter_rust_bridge::IntoDart for FrbWrapper<crate::bindings::AesSuccessActionData> {
     fn into_dart(self) -> flutter_rust_bridge::for_generated::DartAbi {
@@ -4527,6 +4615,7 @@ impl flutter_rust_bridge::IntoDart for crate::model::Config {
                 .into_dart(),
             self.zero_conf_max_amount_sat.into_into_dart().into_dart(),
             self.breez_api_key.into_into_dart().into_dart(),
+            self.external_input_parsers.into_into_dart().into_dart(),
         ]
         .into_dart()
     }
@@ -6401,6 +6490,13 @@ impl SseEncode for BindingLiquidSdk {
     }
 }
 
+impl SseEncode for ExternalInputParser {
+    // Codec=Sse (Serialization based), see doc to use other codecs
+    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
+        <RustOpaqueNom<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<ExternalInputParser>>>::sse_encode(flutter_rust_bridge::for_generated::rust_auto_opaque_encode::<_, StdArc<_>>(self), serializer);
+    }
+}
+
 impl SseEncode
     for RustOpaqueNom<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<BindingLiquidSdk>>
 {
@@ -6412,6 +6508,17 @@ impl SseEncode
     }
 }
 
+impl SseEncode
+    for RustOpaqueNom<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<ExternalInputParser>>
+{
+    // Codec=Sse (Serialization based), see doc to use other codecs
+    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
+        let (ptr, size) = self.sse_encode_raw();
+        <usize>::sse_encode(ptr, serializer);
+        <i32>::sse_encode(size, serializer);
+    }
+}
+
 impl SseEncode
     for StreamSink<crate::model::LogEntry, flutter_rust_bridge::for_generated::DcoCodec>
 {
@@ -6580,6 +6687,7 @@ impl SseEncode for crate::model::Config {
         <u32>::sse_encode(self.zero_conf_min_fee_rate_msat, serializer);
         <Option<u64>>::sse_encode(self.zero_conf_max_amount_sat, serializer);
         <Option<String>>::sse_encode(self.breez_api_key, serializer);
+        <Option<Vec<ExternalInputParser>>>::sse_encode(self.external_input_parsers, serializer);
     }
 }
 
@@ -6755,6 +6863,16 @@ impl SseEncode for crate::model::LiquidNetwork {
     }
 }
 
+impl SseEncode for Vec<ExternalInputParser> {
+    // Codec=Sse (Serialization based), see doc to use other codecs
+    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
+        <i32>::sse_encode(self.len() as _, serializer);
+        for item in self {
+            <ExternalInputParser>::sse_encode(item, serializer);
+        }
+    }
+}
+
 impl SseEncode for Vec<String> {
     // Codec=Sse (Serialization based), see doc to use other codecs
     fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
@@ -7402,6 +7520,16 @@ impl SseEncode for Option<u64> {
     }
 }
 
+impl SseEncode for Option<Vec<ExternalInputParser>> {
+    // Codec=Sse (Serialization based), see doc to use other codecs
+    fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
+        <bool>::sse_encode(self.is_some(), serializer);
+        if let Some(value) = self {
+            <Vec<ExternalInputParser>>::sse_encode(value, serializer);
+        }
+    }
+}
+
 impl SseEncode for Option<Vec<crate::model::PaymentType>> {
     // Codec=Sse (Serialization based), see doc to use other codecs
     fn sse_encode(self, serializer: &mut flutter_rust_bridge::for_generated::SseSerializer) {
@@ -8073,6 +8201,7 @@ mod io {
     use super::*;
     use crate::bindings::*;
     use crate::model::EventListener;
+    use crate::*;
     use flutter_rust_bridge::for_generated::byteorder::{
         NativeEndian, ReadBytesExt, WriteBytesExt,
     };
@@ -8105,6 +8234,18 @@ mod io {
             ))
         }
     }
+    impl CstDecode<ExternalInputParser> for usize {
+        // Codec=Cst (C-struct based), see doc to use other codecs
+        fn cst_decode(self) -> ExternalInputParser {
+            flutter_rust_bridge::for_generated::rust_auto_opaque_decode_owned(CstDecode::<
+                RustOpaqueNom<
+                    flutter_rust_bridge::for_generated::RustAutoOpaqueInner<ExternalInputParser>,
+                >,
+            >::cst_decode(
+                self
+            ))
+        }
+    }
     impl
         CstDecode<
             RustOpaqueNom<
@@ -8120,6 +8261,22 @@ mod io {
             unsafe { decode_rust_opaque_nom(self as _) }
         }
     }
+    impl
+        CstDecode<
+            RustOpaqueNom<
+                flutter_rust_bridge::for_generated::RustAutoOpaqueInner<ExternalInputParser>,
+            >,
+        > for usize
+    {
+        // Codec=Cst (C-struct based), see doc to use other codecs
+        fn cst_decode(
+            self,
+        ) -> RustOpaqueNom<
+            flutter_rust_bridge::for_generated::RustAutoOpaqueInner<ExternalInputParser>,
+        > {
+            unsafe { decode_rust_opaque_nom(self as _) }
+        }
+    }
     impl CstDecode<StreamSink<crate::model::LogEntry, flutter_rust_bridge::for_generated::DcoCodec>>
         for *mut wire_cst_list_prim_u_8_strict
     {
@@ -8644,6 +8801,7 @@ mod io {
                 zero_conf_min_fee_rate_msat: self.zero_conf_min_fee_rate_msat.cst_decode(),
                 zero_conf_max_amount_sat: self.zero_conf_max_amount_sat.cst_decode(),
                 breez_api_key: self.breez_api_key.cst_decode(),
+                external_input_parsers: self.external_input_parsers.cst_decode(),
             }
         }
     }
@@ -8807,6 +8965,16 @@ mod io {
             }
         }
     }
+    impl CstDecode<Vec<ExternalInputParser>> for *mut wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser {
+            // Codec=Cst (C-struct based), see doc to use other codecs
+            fn cst_decode(self) -> Vec<ExternalInputParser> {
+                let vec = unsafe {
+        let wrap = flutter_rust_bridge::for_generated::box_from_leak_ptr(self);
+        flutter_rust_bridge::for_generated::vec_from_leak_ptr(wrap.ptr, wrap.len)
+    };
+    vec.into_iter().map(CstDecode::cst_decode).collect()
+            }
+        }
     impl CstDecode<Vec<String>> for *mut wire_cst_list_String {
         // Codec=Cst (C-struct based), see doc to use other codecs
         fn cst_decode(self) -> Vec<String> {
@@ -10078,6 +10246,7 @@ mod io {
                 zero_conf_min_fee_rate_msat: Default::default(),
                 zero_conf_max_amount_sat: core::ptr::null_mut(),
                 breez_api_key: core::ptr::null_mut(),
+                external_input_parsers: core::ptr::null_mut(),
             }
         }
     }
@@ -11231,6 +11400,15 @@ mod io {
         wire__crate__bindings__BindingLiquidSdk_lnurl_withdraw_impl(port_, that, req)
     }
 
+    #[no_mangle]
+    pub extern "C" fn frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_parse(
+        port_: i64,
+        that: usize,
+        input: *mut wire_cst_list_prim_u_8_strict,
+    ) {
+        wire__crate__bindings__BindingLiquidSdk_parse_impl(port_, that, input)
+    }
+
     #[no_mangle]
     pub extern "C" fn frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_pay_onchain(
         port_: i64,
@@ -11411,14 +11589,6 @@ mod io {
         wire__crate__bindings__default_config_impl(network, breez_api_key)
     }
 
-    #[no_mangle]
-    pub extern "C" fn frbgen_breez_liquid_wire__crate__bindings__parse(
-        port_: i64,
-        input: *mut wire_cst_list_prim_u_8_strict,
-    ) {
-        wire__crate__bindings__parse_impl(port_, input)
-    }
-
     #[no_mangle]
     pub extern "C" fn frbgen_breez_liquid_wire__crate__bindings__parse_invoice(
         input: *mut wire_cst_list_prim_u_8_strict,
@@ -11444,6 +11614,24 @@ mod io {
         }
     }
 
+    #[no_mangle]
+    pub extern "C" fn frbgen_breez_liquid_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+        ptr: *const std::ffi::c_void,
+    ) {
+        unsafe {
+            StdArc::<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<ExternalInputParser>>::increment_strong_count(ptr as _);
+        }
+    }
+
+    #[no_mangle]
+    pub extern "C" fn frbgen_breez_liquid_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+        ptr: *const std::ffi::c_void,
+    ) {
+        unsafe {
+            StdArc::<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<ExternalInputParser>>::decrement_strong_count(ptr as _);
+        }
+    }
+
     #[no_mangle]
     pub extern "C" fn frbgen_breez_liquid_cst_new_box_autoadd_aes_success_action_data(
     ) -> *mut wire_cst_aes_success_action_data {
@@ -11815,6 +12003,12 @@ mod io {
         )
     }
 
+    #[no_mangle]
+    pub extern "C" fn frbgen_breez_liquid_cst_new_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(len: i32) -> *mut wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser{
+        let wrap = wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser { ptr: flutter_rust_bridge::for_generated::new_leak_vec_ptr(Default::default(), len), len };
+        flutter_rust_bridge::for_generated::new_leak_box_ptr(wrap)
+    }
+
     #[no_mangle]
     pub extern "C" fn frbgen_breez_liquid_cst_new_list_String(
         len: i32,
@@ -12074,18 +12268,17 @@ mod io {
     }
     #[repr(C)]
     #[derive(Clone, Copy)]
-    pub struct wire_cst_config {
-        liquid_electrum_url: *mut wire_cst_list_prim_u_8_strict,
-        bitcoin_electrum_url: *mut wire_cst_list_prim_u_8_strict,
-        mempoolspace_url: *mut wire_cst_list_prim_u_8_strict,
-        working_dir: *mut wire_cst_list_prim_u_8_strict,
-        cache_dir: *mut wire_cst_list_prim_u_8_strict,
-        network: i32,
-        payment_timeout_sec: u64,
-        zero_conf_min_fee_rate_msat: u32,
-        zero_conf_max_amount_sat: *mut u64,
-        breez_api_key: *mut wire_cst_list_prim_u_8_strict,
-    }
+    pub struct wire_cst_config { liquid_electrum_url: *mut wire_cst_list_prim_u_8_strict,
+bitcoin_electrum_url: *mut wire_cst_list_prim_u_8_strict,
+mempoolspace_url: *mut wire_cst_list_prim_u_8_strict,
+working_dir: *mut wire_cst_list_prim_u_8_strict,
+cache_dir: *mut wire_cst_list_prim_u_8_strict,
+network: i32,
+payment_timeout_sec: u64,
+zero_conf_min_fee_rate_msat: u32,
+zero_conf_max_amount_sat: *mut u64,
+breez_api_key: *mut wire_cst_list_prim_u_8_strict,
+external_input_parsers: *mut wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser }
     #[repr(C)]
     #[derive(Clone, Copy)]
     pub struct wire_cst_connect_request {
@@ -12231,6 +12424,13 @@ mod io {
     }
     #[repr(C)]
     #[derive(Clone, Copy)]
+    pub struct wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser
+    {
+        ptr: *mut usize,
+        len: i32,
+    }
+    #[repr(C)]
+    #[derive(Clone, Copy)]
     pub struct wire_cst_list_String {
         ptr: *mut *mut wire_cst_list_prim_u_8_strict,
         len: i32,
diff --git a/lib/core/src/model.rs b/lib/core/src/model.rs
index afeb4a17..608ee507 100644
--- a/lib/core/src/model.rs
+++ b/lib/core/src/model.rs
@@ -53,6 +53,10 @@ pub struct Config {
     pub zero_conf_max_amount_sat: Option<u64>,
     /// The Breez API key used for making requests to their mempool service
     pub breez_api_key: Option<String>,
+    /// A set of external input parsers that are used by [LiquidSdk::parse] when the input
+    /// is not recognized. See [ExternalInputParser] for more details on how to configure
+    /// external parsing.
+    pub external_input_parsers: Option<Vec<ExternalInputParser>>,
 }
 
 impl Config {
@@ -68,6 +72,7 @@ impl Config {
             zero_conf_min_fee_rate_msat: DEFAULT_ZERO_CONF_MIN_FEE_RATE_MAINNET,
             zero_conf_max_amount_sat: None,
             breez_api_key: Some(breez_api_key),
+            external_input_parsers: None,
         }
     }
 
@@ -83,6 +88,7 @@ impl Config {
             zero_conf_min_fee_rate_msat: DEFAULT_ZERO_CONF_MIN_FEE_RATE_TESTNET,
             zero_conf_max_amount_sat: None,
             breez_api_key,
+            external_input_parsers: None,
         }
     }
 
diff --git a/lib/core/src/sdk.rs b/lib/core/src/sdk.rs
index d6ad914c..34a8d168 100644
--- a/lib/core/src/sdk.rs
+++ b/lib/core/src/sdk.rs
@@ -1,7 +1,3 @@
-use std::collections::HashMap;
-use std::time::Instant;
-use std::{fs, path::PathBuf, str::FromStr, sync::Arc, time::Duration};
-
 use anyhow::{anyhow, Result};
 use boltz_client::{swaps::boltz::*, util::secrets::Preimage};
 use buy::{BuyBitcoinApi, BuyBitcoinService};
@@ -23,6 +19,9 @@ use sdk_common::input_parser::InputType;
 use sdk_common::liquid::LiquidAddressData;
 use sdk_common::prelude::{FiatAPI, FiatCurrency, LnUrlPayError, LnUrlWithdrawError, Rate};
 use signer::SdkSigner;
+use std::collections::HashMap;
+use std::time::Instant;
+use std::{fs, path::PathBuf, str::FromStr, sync::Arc, time::Duration};
 use tokio::sync::{watch, Mutex, RwLock};
 use tokio::time::MissedTickBehavior;
 use tokio_stream::wrappers::BroadcastStream;
@@ -574,7 +573,7 @@ impl LiquidSdk {
     }
 
     async fn validate_bitcoin_address(&self, input: &str) -> Result<String, PaymentError> {
-        match sdk::LiquidSdk::parse(input).await? {
+        match self.parse(input).await? {
             InputType::BitcoinAddress {
                 address: bitcoin_address_data,
                 ..
@@ -823,7 +822,7 @@ impl LiquidSdk {
         let receiver_amount_sat;
         let payment_destination;
 
-        match Self::parse(&req.destination).await {
+        match self.parse(&req.destination).await {
             Ok(InputType::LiquidAddress {
                 address: mut liquid_address_data,
             }) => {
@@ -2693,7 +2692,9 @@ impl LiquidSdk {
     }
 
     /// Parses a string into an [InputType]. See [input_parser::parse].
-    pub async fn parse(input: &str) -> Result<InputType, PaymentError> {
+    ///
+    /// Can optionally be configured to use external input parsers by providing `external_input_parsers` in [Config].
+    pub async fn parse(&self, input: &str) -> Result<InputType, PaymentError> {
         if let Ok(offer) = input.parse::<Offer>() {
             // TODO This conversion (between lightning-v0.0.125 to -v0.0.118 Amount types)
             //      won't be needed when Liquid SDK uses the same lightning crate version as sdk-common
@@ -2748,7 +2749,8 @@ impl LiquidSdk {
             });
         }
 
-        parse(input)
+        let external_parsers = &self.config.external_input_parsers;
+        parse(input, external_parsers.as_deref())
             .await
             .map_err(|e| PaymentError::generic(&e.to_string()))
     }
diff --git a/packages/dart/lib/src/bindings.dart b/packages/dart/lib/src/bindings.dart
index 655064b6..bf946fbd 100644
--- a/packages/dart/lib/src/bindings.dart
+++ b/packages/dart/lib/src/bindings.dart
@@ -6,6 +6,7 @@
 import 'bindings/duplicates.dart';
 import 'error.dart';
 import 'frb_generated.dart';
+import 'lib.dart';
 import 'model.dart';
 import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
 import 'package:freezed_annotation/freezed_annotation.dart' hide protected;
@@ -24,8 +25,6 @@ Stream<LogEntry> breezLogStream() => RustLib.instance.api.crateBindingsBreezLogS
 Config defaultConfig({required LiquidNetwork network, String? breezApiKey}) =>
     RustLib.instance.api.crateBindingsDefaultConfig(network: network, breezApiKey: breezApiKey);
 
-Future<InputType> parse({required String input}) => RustLib.instance.api.crateBindingsParse(input: input);
-
 LNInvoice parseInvoice({required String input}) =>
     RustLib.instance.api.crateBindingsParseInvoice(input: input);
 
@@ -65,6 +64,8 @@ abstract class BindingLiquidSdk implements RustOpaqueInterface {
 
   Future<LnUrlWithdrawResult> lnurlWithdraw({required LnUrlWithdrawRequest req});
 
+  Future<InputType> parse({required String input});
+
   Future<SendPaymentResponse> payOnchain({required PayOnchainRequest req});
 
   Future<PrepareBuyBitcoinResponse> prepareBuyBitcoin({required PrepareBuyBitcoinRequest req});
diff --git a/packages/dart/lib/src/frb_generated.dart b/packages/dart/lib/src/frb_generated.dart
index 97887a9b..80fb01ec 100644
--- a/packages/dart/lib/src/frb_generated.dart
+++ b/packages/dart/lib/src/frb_generated.dart
@@ -10,6 +10,7 @@ import 'dart:convert';
 import 'error.dart';
 import 'frb_generated.dart';
 import 'frb_generated.io.dart' if (dart.library.js_interop) 'frb_generated.web.dart';
+import 'lib.dart';
 import 'model.dart';
 import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
 
@@ -65,7 +66,7 @@ class RustLib extends BaseEntrypoint<RustLibApi, RustLibApiImpl, RustLibWire> {
   String get codegenVersion => '2.4.0';
 
   @override
-  int get rustContentHash => 425220482;
+  int get rustContentHash => -2032324171;
 
   static const kDefaultExternalLibraryLoaderConfig = ExternalLibraryLoaderConfig(
     stem: 'breez_sdk_liquid',
@@ -119,6 +120,9 @@ abstract class RustLibApi extends BaseApi {
   Future<LnUrlWithdrawResult> crateBindingsBindingLiquidSdkLnurlWithdraw(
       {required BindingLiquidSdk that, required LnUrlWithdrawRequest req});
 
+  Future<InputType> crateBindingsBindingLiquidSdkParse(
+      {required BindingLiquidSdk that, required String input});
+
   Future<SendPaymentResponse> crateBindingsBindingLiquidSdkPayOnchain(
       {required BindingLiquidSdk that, required PayOnchainRequest req});
 
@@ -174,8 +178,6 @@ abstract class RustLibApi extends BaseApi {
 
   Config crateBindingsDefaultConfig({required LiquidNetwork network, String? breezApiKey});
 
-  Future<InputType> crateBindingsParse({required String input});
-
   LNInvoice crateBindingsParseInvoice({required String input});
 
   RustArcIncrementStrongCountFnType get rust_arc_increment_strong_count_BindingLiquidSdk;
@@ -183,6 +185,12 @@ abstract class RustLibApi extends BaseApi {
   RustArcDecrementStrongCountFnType get rust_arc_decrement_strong_count_BindingLiquidSdk;
 
   CrossPlatformFinalizerArg get rust_arc_decrement_strong_count_BindingLiquidSdkPtr;
+
+  RustArcIncrementStrongCountFnType get rust_arc_increment_strong_count_ExternalInputParser;
+
+  RustArcDecrementStrongCountFnType get rust_arc_decrement_strong_count_ExternalInputParser;
+
+  CrossPlatformFinalizerArg get rust_arc_decrement_strong_count_ExternalInputParserPtr;
 }
 
 class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
@@ -623,6 +631,32 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
         argNames: ["that", "req"],
       );
 
+  @override
+  Future<InputType> crateBindingsBindingLiquidSdkParse(
+      {required BindingLiquidSdk that, required String input}) {
+    return handler.executeNormal(NormalTask(
+      callFfi: (port_) {
+        var arg0 =
+            cst_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(
+                that);
+        var arg1 = cst_encode_String(input);
+        return wire.wire__crate__bindings__BindingLiquidSdk_parse(port_, arg0, arg1);
+      },
+      codec: DcoCodec(
+        decodeSuccessData: dco_decode_input_type,
+        decodeErrorData: dco_decode_payment_error,
+      ),
+      constMeta: kCrateBindingsBindingLiquidSdkParseConstMeta,
+      argValues: [that, input],
+      apiImpl: this,
+    ));
+  }
+
+  TaskConstMeta get kCrateBindingsBindingLiquidSdkParseConstMeta => const TaskConstMeta(
+        debugName: "BindingLiquidSdk_parse",
+        argNames: ["that", "input"],
+      );
+
   @override
   Future<SendPaymentResponse> crateBindingsBindingLiquidSdkPayOnchain(
       {required BindingLiquidSdk that, required PayOnchainRequest req}) {
@@ -1150,28 +1184,6 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
         argNames: ["network", "breezApiKey"],
       );
 
-  @override
-  Future<InputType> crateBindingsParse({required String input}) {
-    return handler.executeNormal(NormalTask(
-      callFfi: (port_) {
-        var arg0 = cst_encode_String(input);
-        return wire.wire__crate__bindings__parse(port_, arg0);
-      },
-      codec: DcoCodec(
-        decodeSuccessData: dco_decode_input_type,
-        decodeErrorData: dco_decode_payment_error,
-      ),
-      constMeta: kCrateBindingsParseConstMeta,
-      argValues: [input],
-      apiImpl: this,
-    ));
-  }
-
-  TaskConstMeta get kCrateBindingsParseConstMeta => const TaskConstMeta(
-        debugName: "parse",
-        argNames: ["input"],
-      );
-
   @override
   LNInvoice crateBindingsParseInvoice({required String input}) {
     return handler.executeSync(SyncTask(
@@ -1200,6 +1212,12 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
   RustArcDecrementStrongCountFnType get rust_arc_decrement_strong_count_BindingLiquidSdk => wire
       .rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk;
 
+  RustArcIncrementStrongCountFnType get rust_arc_increment_strong_count_ExternalInputParser => wire
+      .rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser;
+
+  RustArcDecrementStrongCountFnType get rust_arc_decrement_strong_count_ExternalInputParser => wire
+      .rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser;
+
   @protected
   AnyhowException dco_decode_AnyhowException(dynamic raw) {
     // Codec=Dco (DartCObject based), see doc to use other codecs
@@ -1214,6 +1232,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
     return BindingLiquidSdkImpl.frbInternalDcoDecode(raw as List<dynamic>);
   }
 
+  @protected
+  ExternalInputParser
+      dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          dynamic raw) {
+    // Codec=Dco (DartCObject based), see doc to use other codecs
+    return ExternalInputParserImpl.frbInternalDcoDecode(raw as List<dynamic>);
+  }
+
   @protected
   BindingLiquidSdk
       dco_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(
@@ -1229,6 +1255,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
     return BindingLiquidSdkImpl.frbInternalDcoDecode(raw as List<dynamic>);
   }
 
+  @protected
+  ExternalInputParser
+      dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          dynamic raw) {
+    // Codec=Dco (DartCObject based), see doc to use other codecs
+    return ExternalInputParserImpl.frbInternalDcoDecode(raw as List<dynamic>);
+  }
+
   @protected
   RustStreamSink<LogEntry> dco_decode_StreamSink_log_entry_Dco(dynamic raw) {
     // Codec=Dco (DartCObject based), see doc to use other codecs
@@ -1688,7 +1722,7 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
   Config dco_decode_config(dynamic raw) {
     // Codec=Dco (DartCObject based), see doc to use other codecs
     final arr = raw as List<dynamic>;
-    if (arr.length != 10) throw Exception('unexpected arr length: expect 10 but see ${arr.length}');
+    if (arr.length != 11) throw Exception('unexpected arr length: expect 11 but see ${arr.length}');
     return Config(
       liquidElectrumUrl: dco_decode_String(arr[0]),
       bitcoinElectrumUrl: dco_decode_String(arr[1]),
@@ -1700,6 +1734,9 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
       zeroConfMinFeeRateMsat: dco_decode_u_32(arr[7]),
       zeroConfMaxAmountSat: dco_decode_opt_box_autoadd_u_64(arr[8]),
       breezApiKey: dco_decode_opt_String(arr[9]),
+      externalInputParsers:
+          dco_decode_opt_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+              arr[10]),
     );
   }
 
@@ -1879,6 +1916,17 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
     return LiquidNetwork.values[raw as int];
   }
 
+  @protected
+  List<ExternalInputParser>
+      dco_decode_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          dynamic raw) {
+    // Codec=Dco (DartCObject based), see doc to use other codecs
+    return (raw as List<dynamic>)
+        .map(
+            dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser)
+        .toList();
+  }
+
   @protected
   List<String> dco_decode_list_String(dynamic raw) {
     // Codec=Dco (DartCObject based), see doc to use other codecs
@@ -2445,6 +2493,17 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
     return raw == null ? null : dco_decode_box_autoadd_u_64(raw);
   }
 
+  @protected
+  List<ExternalInputParser>?
+      dco_decode_opt_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          dynamic raw) {
+    // Codec=Dco (DartCObject based), see doc to use other codecs
+    return raw == null
+        ? null
+        : dco_decode_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+            raw);
+  }
+
   @protected
   List<PaymentType>? dco_decode_opt_list_payment_type(dynamic raw) {
     // Codec=Dco (DartCObject based), see doc to use other codecs
@@ -3114,6 +3173,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
         sse_decode_usize(deserializer), sse_decode_i_32(deserializer));
   }
 
+  @protected
+  ExternalInputParser
+      sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          SseDeserializer deserializer) {
+    // Codec=Sse (Serialization based), see doc to use other codecs
+    return ExternalInputParserImpl.frbInternalSseDecode(
+        sse_decode_usize(deserializer), sse_decode_i_32(deserializer));
+  }
+
   @protected
   BindingLiquidSdk
       sse_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(
@@ -3131,6 +3199,15 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
         sse_decode_usize(deserializer), sse_decode_i_32(deserializer));
   }
 
+  @protected
+  ExternalInputParser
+      sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          SseDeserializer deserializer) {
+    // Codec=Sse (Serialization based), see doc to use other codecs
+    return ExternalInputParserImpl.frbInternalSseDecode(
+        sse_decode_usize(deserializer), sse_decode_i_32(deserializer));
+  }
+
   @protected
   RustStreamSink<LogEntry> sse_decode_StreamSink_log_entry_Dco(SseDeserializer deserializer) {
     // Codec=Sse (Serialization based), see doc to use other codecs
@@ -3584,6 +3661,9 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
     var var_zeroConfMinFeeRateMsat = sse_decode_u_32(deserializer);
     var var_zeroConfMaxAmountSat = sse_decode_opt_box_autoadd_u_64(deserializer);
     var var_breezApiKey = sse_decode_opt_String(deserializer);
+    var var_externalInputParsers =
+        sse_decode_opt_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+            deserializer);
     return Config(
         liquidElectrumUrl: var_liquidElectrumUrl,
         bitcoinElectrumUrl: var_bitcoinElectrumUrl,
@@ -3594,7 +3674,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
         paymentTimeoutSec: var_paymentTimeoutSec,
         zeroConfMinFeeRateMsat: var_zeroConfMinFeeRateMsat,
         zeroConfMaxAmountSat: var_zeroConfMaxAmountSat,
-        breezApiKey: var_breezApiKey);
+        breezApiKey: var_breezApiKey,
+        externalInputParsers: var_externalInputParsers);
   }
 
   @protected
@@ -3764,6 +3845,22 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
     return LiquidNetwork.values[inner];
   }
 
+  @protected
+  List<ExternalInputParser>
+      sse_decode_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          SseDeserializer deserializer) {
+    // Codec=Sse (Serialization based), see doc to use other codecs
+
+    var len_ = sse_decode_i_32(deserializer);
+    var ans_ = <ExternalInputParser>[];
+    for (var idx_ = 0; idx_ < len_; ++idx_) {
+      ans_.add(
+          sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+              deserializer));
+    }
+    return ans_;
+  }
+
   @protected
   List<String> sse_decode_list_String(SseDeserializer deserializer) {
     // Codec=Sse (Serialization based), see doc to use other codecs
@@ -4434,6 +4531,20 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
     }
   }
 
+  @protected
+  List<ExternalInputParser>?
+      sse_decode_opt_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          SseDeserializer deserializer) {
+    // Codec=Sse (Serialization based), see doc to use other codecs
+
+    if (sse_decode_bool(deserializer)) {
+      return (sse_decode_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          deserializer));
+    } else {
+      return null;
+    }
+  }
+
   @protected
   List<PaymentType>? sse_decode_opt_list_payment_type(SseDeserializer deserializer) {
     // Codec=Sse (Serialization based), see doc to use other codecs
@@ -5054,6 +5165,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
     return (raw as BindingLiquidSdkImpl).frbInternalCstEncode(move: true);
   }
 
+  @protected
+  int cst_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+      ExternalInputParser raw) {
+    // Codec=Cst (C-struct based), see doc to use other codecs
+// ignore: invalid_use_of_internal_member
+    return (raw as ExternalInputParserImpl).frbInternalCstEncode(move: true);
+  }
+
   @protected
   int cst_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(
       BindingLiquidSdk raw) {
@@ -5070,6 +5189,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
     return (raw as BindingLiquidSdkImpl).frbInternalCstEncode();
   }
 
+  @protected
+  int cst_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+      ExternalInputParser raw) {
+    // Codec=Cst (C-struct based), see doc to use other codecs
+// ignore: invalid_use_of_internal_member
+    return (raw as ExternalInputParserImpl).frbInternalCstEncode();
+  }
+
   @protected
   bool cst_encode_bool(bool raw) {
     // Codec=Cst (C-struct based), see doc to use other codecs
@@ -5161,6 +5288,14 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
     sse_encode_usize((self as BindingLiquidSdkImpl).frbInternalSseEncode(move: true), serializer);
   }
 
+  @protected
+  void
+      sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          ExternalInputParser self, SseSerializer serializer) {
+    // Codec=Sse (Serialization based), see doc to use other codecs
+    sse_encode_usize((self as ExternalInputParserImpl).frbInternalSseEncode(move: true), serializer);
+  }
+
   @protected
   void sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(
       BindingLiquidSdk self, SseSerializer serializer) {
@@ -5175,6 +5310,13 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
     sse_encode_usize((self as BindingLiquidSdkImpl).frbInternalSseEncode(move: null), serializer);
   }
 
+  @protected
+  void sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+      ExternalInputParser self, SseSerializer serializer) {
+    // Codec=Sse (Serialization based), see doc to use other codecs
+    sse_encode_usize((self as ExternalInputParserImpl).frbInternalSseEncode(move: null), serializer);
+  }
+
   @protected
   void sse_encode_StreamSink_log_entry_Dco(RustStreamSink<LogEntry> self, SseSerializer serializer) {
     // Codec=Sse (Serialization based), see doc to use other codecs
@@ -5629,6 +5771,8 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
     sse_encode_u_32(self.zeroConfMinFeeRateMsat, serializer);
     sse_encode_opt_box_autoadd_u_64(self.zeroConfMaxAmountSat, serializer);
     sse_encode_opt_String(self.breezApiKey, serializer);
+    sse_encode_opt_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+        self.externalInputParsers, serializer);
   }
 
   @protected
@@ -5769,6 +5913,18 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
     sse_encode_i_32(self.index, serializer);
   }
 
+  @protected
+  void
+      sse_encode_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          List<ExternalInputParser> self, SseSerializer serializer) {
+    // Codec=Sse (Serialization based), see doc to use other codecs
+    sse_encode_i_32(self.length, serializer);
+    for (final item in self) {
+      sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          item, serializer);
+    }
+  }
+
   @protected
   void sse_encode_list_String(List<String> self, SseSerializer serializer) {
     // Codec=Sse (Serialization based), see doc to use other codecs
@@ -6322,6 +6478,19 @@ class RustLibApiImpl extends RustLibApiImplPlatform implements RustLibApi {
     }
   }
 
+  @protected
+  void
+      sse_encode_opt_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          List<ExternalInputParser>? self, SseSerializer serializer) {
+    // Codec=Sse (Serialization based), see doc to use other codecs
+
+    sse_encode_bool(self != null, serializer);
+    if (self != null) {
+      sse_encode_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          self, serializer);
+    }
+  }
+
   @protected
   void sse_encode_opt_list_payment_type(List<PaymentType>? self, SseSerializer serializer) {
     // Codec=Sse (Serialization based), see doc to use other codecs
@@ -6922,6 +7091,9 @@ class BindingLiquidSdkImpl extends RustOpaque implements BindingLiquidSdk {
   Future<LnUrlWithdrawResult> lnurlWithdraw({required LnUrlWithdrawRequest req}) =>
       RustLib.instance.api.crateBindingsBindingLiquidSdkLnurlWithdraw(that: this, req: req);
 
+  Future<InputType> parse({required String input}) =>
+      RustLib.instance.api.crateBindingsBindingLiquidSdkParse(that: this, input: input);
+
   Future<SendPaymentResponse> payOnchain({required PayOnchainRequest req}) =>
       RustLib.instance.api.crateBindingsBindingLiquidSdkPayOnchain(that: this, req: req);
 
@@ -6978,3 +7150,21 @@ class BindingLiquidSdkImpl extends RustOpaque implements BindingLiquidSdk {
         that: this,
       );
 }
+
+@sealed
+class ExternalInputParserImpl extends RustOpaque implements ExternalInputParser {
+  // Not to be used by end users
+  ExternalInputParserImpl.frbInternalDcoDecode(List<dynamic> wire)
+      : super.frbInternalDcoDecode(wire, _kStaticData);
+
+  // Not to be used by end users
+  ExternalInputParserImpl.frbInternalSseDecode(BigInt ptr, int externalSizeOnNative)
+      : super.frbInternalSseDecode(ptr, externalSizeOnNative, _kStaticData);
+
+  static final _kStaticData = RustArcStaticData(
+    rustArcIncrementStrongCount: RustLib.instance.api.rust_arc_increment_strong_count_ExternalInputParser,
+    rustArcDecrementStrongCount: RustLib.instance.api.rust_arc_decrement_strong_count_ExternalInputParser,
+    rustArcDecrementStrongCountPtr:
+        RustLib.instance.api.rust_arc_decrement_strong_count_ExternalInputParserPtr,
+  );
+}
diff --git a/packages/dart/lib/src/frb_generated.io.dart b/packages/dart/lib/src/frb_generated.io.dart
index 1b5e6b0b..5dd1c68a 100644
--- a/packages/dart/lib/src/frb_generated.io.dart
+++ b/packages/dart/lib/src/frb_generated.io.dart
@@ -10,6 +10,7 @@ import 'dart:convert';
 import 'dart:ffi' as ffi;
 import 'error.dart';
 import 'frb_generated.dart';
+import 'lib.dart';
 import 'model.dart';
 import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated_io.dart';
 
@@ -24,6 +25,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
   CrossPlatformFinalizerArg get rust_arc_decrement_strong_count_BindingLiquidSdkPtr => wire
       ._rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdkPtr;
 
+  CrossPlatformFinalizerArg get rust_arc_decrement_strong_count_ExternalInputParserPtr => wire
+      ._rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParserPtr;
+
   @protected
   AnyhowException dco_decode_AnyhowException(dynamic raw);
 
@@ -32,6 +36,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
       dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(
           dynamic raw);
 
+  @protected
+  ExternalInputParser
+      dco_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          dynamic raw);
+
   @protected
   BindingLiquidSdk
       dco_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(
@@ -41,6 +50,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
   BindingLiquidSdk dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(
       dynamic raw);
 
+  @protected
+  ExternalInputParser
+      dco_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          dynamic raw);
+
   @protected
   RustStreamSink<LogEntry> dco_decode_StreamSink_log_entry_Dco(dynamic raw);
 
@@ -278,6 +292,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
   @protected
   LiquidNetwork dco_decode_liquid_network(dynamic raw);
 
+  @protected
+  List<ExternalInputParser>
+      dco_decode_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          dynamic raw);
+
   @protected
   List<String> dco_decode_list_String(dynamic raw);
 
@@ -431,6 +450,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
   @protected
   BigInt? dco_decode_opt_box_autoadd_u_64(dynamic raw);
 
+  @protected
+  List<ExternalInputParser>?
+      dco_decode_opt_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          dynamic raw);
+
   @protected
   List<PaymentType>? dco_decode_opt_list_payment_type(dynamic raw);
 
@@ -583,6 +607,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
       sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(
           SseDeserializer deserializer);
 
+  @protected
+  ExternalInputParser
+      sse_decode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          SseDeserializer deserializer);
+
   @protected
   BindingLiquidSdk
       sse_decode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(
@@ -592,6 +621,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
   BindingLiquidSdk sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(
       SseDeserializer deserializer);
 
+  @protected
+  ExternalInputParser
+      sse_decode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          SseDeserializer deserializer);
+
   @protected
   RustStreamSink<LogEntry> sse_decode_StreamSink_log_entry_Dco(SseDeserializer deserializer);
 
@@ -831,6 +865,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
   @protected
   LiquidNetwork sse_decode_liquid_network(SseDeserializer deserializer);
 
+  @protected
+  List<ExternalInputParser>
+      sse_decode_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          SseDeserializer deserializer);
+
   @protected
   List<String> sse_decode_list_String(SseDeserializer deserializer);
 
@@ -984,6 +1023,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
   @protected
   BigInt? sse_decode_opt_box_autoadd_u_64(SseDeserializer deserializer);
 
+  @protected
+  List<ExternalInputParser>?
+      sse_decode_opt_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          SseDeserializer deserializer);
+
   @protected
   List<PaymentType>? sse_decode_opt_list_payment_type(SseDeserializer deserializer);
 
@@ -1589,6 +1633,23 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
     return raw.toInt();
   }
 
+  @protected
+  ffi.Pointer<
+          wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser>
+      cst_encode_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          List<ExternalInputParser> raw) {
+    // Codec=Cst (C-struct based), see doc to use other codecs
+    final ans = wire
+        .cst_new_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+            raw.length);
+    for (var i = 0; i < raw.length; ++i) {
+      ans.ref.ptr[i] =
+          cst_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+              raw[i]);
+    }
+    return ans;
+  }
+
   @protected
   ffi.Pointer<wire_cst_list_String> cst_encode_list_String(List<String> raw) {
     // Codec=Cst (C-struct based), see doc to use other codecs
@@ -1788,6 +1849,18 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
     return raw == null ? ffi.nullptr : cst_encode_box_autoadd_u_64(raw);
   }
 
+  @protected
+  ffi.Pointer<
+          wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser>
+      cst_encode_opt_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          List<ExternalInputParser>? raw) {
+    // Codec=Cst (C-struct based), see doc to use other codecs
+    return raw == null
+        ? ffi.nullptr
+        : cst_encode_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+            raw);
+  }
+
   @protected
   ffi.Pointer<wire_cst_list_payment_type> cst_encode_opt_list_payment_type(List<PaymentType>? raw) {
     // Codec=Cst (C-struct based), see doc to use other codecs
@@ -2175,6 +2248,9 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
     wireObj.zero_conf_min_fee_rate_msat = cst_encode_u_32(apiObj.zeroConfMinFeeRateMsat);
     wireObj.zero_conf_max_amount_sat = cst_encode_opt_box_autoadd_u_64(apiObj.zeroConfMaxAmountSat);
     wireObj.breez_api_key = cst_encode_opt_String(apiObj.breezApiKey);
+    wireObj.external_input_parsers =
+        cst_encode_opt_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+            apiObj.externalInputParsers);
   }
 
   @protected
@@ -3204,6 +3280,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
   int cst_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(
       BindingLiquidSdk raw);
 
+  @protected
+  int cst_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+      ExternalInputParser raw);
+
   @protected
   int cst_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(
       BindingLiquidSdk raw);
@@ -3212,6 +3292,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
   int cst_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(
       BindingLiquidSdk raw);
 
+  @protected
+  int cst_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+      ExternalInputParser raw);
+
   @protected
   bool cst_encode_bool(bool raw);
 
@@ -3258,6 +3342,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
   void sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(
       BindingLiquidSdk self, SseSerializer serializer);
 
+  @protected
+  void
+      sse_encode_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          ExternalInputParser self, SseSerializer serializer);
+
   @protected
   void sse_encode_Auto_Ref_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(
       BindingLiquidSdk self, SseSerializer serializer);
@@ -3266,6 +3355,10 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
   void sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdk(
       BindingLiquidSdk self, SseSerializer serializer);
 
+  @protected
+  void sse_encode_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+      ExternalInputParser self, SseSerializer serializer);
+
   @protected
   void sse_encode_StreamSink_log_entry_Dco(RustStreamSink<LogEntry> self, SseSerializer serializer);
 
@@ -3513,6 +3606,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
   @protected
   void sse_encode_liquid_network(LiquidNetwork self, SseSerializer serializer);
 
+  @protected
+  void
+      sse_encode_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          List<ExternalInputParser> self, SseSerializer serializer);
+
   @protected
   void sse_encode_list_String(List<String> self, SseSerializer serializer);
 
@@ -3668,6 +3766,11 @@ abstract class RustLibApiImplPlatform extends BaseApiImpl<RustLibWire> {
   @protected
   void sse_encode_opt_box_autoadd_u_64(BigInt? self, SseSerializer serializer);
 
+  @protected
+  void
+      sse_encode_opt_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+          List<ExternalInputParser>? self, SseSerializer serializer);
+
   @protected
   void sse_encode_opt_list_payment_type(List<PaymentType>? self, SseSerializer serializer);
 
@@ -4152,6 +4255,26 @@ class RustLibWire implements BaseWire {
       _wire__crate__bindings__BindingLiquidSdk_lnurl_withdrawPtr
           .asFunction<void Function(int, int, ffi.Pointer<wire_cst_ln_url_withdraw_request>)>();
 
+  void wire__crate__bindings__BindingLiquidSdk_parse(
+    int port_,
+    int that,
+    ffi.Pointer<wire_cst_list_prim_u_8_strict> input,
+  ) {
+    return _wire__crate__bindings__BindingLiquidSdk_parse(
+      port_,
+      that,
+      input,
+    );
+  }
+
+  late final _wire__crate__bindings__BindingLiquidSdk_parsePtr = _lookup<
+          ffi.NativeFunction<
+              ffi.Void Function(ffi.Int64, ffi.UintPtr, ffi.Pointer<wire_cst_list_prim_u_8_strict>)>>(
+      'frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_parse');
+  late final _wire__crate__bindings__BindingLiquidSdk_parse =
+      _wire__crate__bindings__BindingLiquidSdk_parsePtr
+          .asFunction<void Function(int, int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)>();
+
   void wire__crate__bindings__BindingLiquidSdk_pay_onchain(
     int port_,
     int that,
@@ -4543,22 +4666,6 @@ class RustLibWire implements BaseWire {
   late final _wire__crate__bindings__default_config = _wire__crate__bindings__default_configPtr
       .asFunction<WireSyncRust2DartDco Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)>();
 
-  void wire__crate__bindings__parse(
-    int port_,
-    ffi.Pointer<wire_cst_list_prim_u_8_strict> input,
-  ) {
-    return _wire__crate__bindings__parse(
-      port_,
-      input,
-    );
-  }
-
-  late final _wire__crate__bindings__parsePtr =
-      _lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64, ffi.Pointer<wire_cst_list_prim_u_8_strict>)>>(
-          'frbgen_breez_liquid_wire__crate__bindings__parse');
-  late final _wire__crate__bindings__parse = _wire__crate__bindings__parsePtr
-      .asFunction<void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)>();
-
   WireSyncRust2DartDco wire__crate__bindings__parse_invoice(
     ffi.Pointer<wire_cst_list_prim_u_8_strict> input,
   ) {
@@ -4605,6 +4712,38 @@ class RustLibWire implements BaseWire {
       _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdkPtr
           .asFunction<void Function(ffi.Pointer<ffi.Void>)>();
 
+  void
+      rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+    ffi.Pointer<ffi.Void> ptr,
+  ) {
+    return _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+      ptr,
+    );
+  }
+
+  late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParserPtr =
+      _lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
+          'frbgen_breez_liquid_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser');
+  late final _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser =
+      _rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParserPtr
+          .asFunction<void Function(ffi.Pointer<ffi.Void>)>();
+
+  void
+      rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+    ffi.Pointer<ffi.Void> ptr,
+  ) {
+    return _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+      ptr,
+    );
+  }
+
+  late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParserPtr =
+      _lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
+          'frbgen_breez_liquid_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser');
+  late final _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser =
+      _rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParserPtr
+          .asFunction<void Function(ffi.Pointer<ffi.Void>)>();
+
   ffi.Pointer<wire_cst_aes_success_action_data> cst_new_box_autoadd_aes_success_action_data() {
     return _cst_new_box_autoadd_aes_success_action_data();
   }
@@ -5134,6 +5273,30 @@ class RustLibWire implements BaseWire {
   late final _cst_new_box_autoadd_url_success_action_data = _cst_new_box_autoadd_url_success_action_dataPtr
       .asFunction<ffi.Pointer<wire_cst_url_success_action_data> Function()>();
 
+  ffi.Pointer<
+          wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser>
+      cst_new_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+    int len,
+  ) {
+    return _cst_new_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+      len,
+    );
+  }
+
+  late final _cst_new_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParserPtr =
+      _lookup<
+              ffi.NativeFunction<
+                  ffi.Pointer<
+                          wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser>
+                      Function(ffi.Int32)>>(
+          'frbgen_breez_liquid_cst_new_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser');
+  late final _cst_new_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser =
+      _cst_new_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParserPtr
+          .asFunction<
+              ffi.Pointer<
+                      wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser>
+                  Function(int)>();
+
   ffi.Pointer<wire_cst_list_String> cst_new_list_String(
     int len,
   ) {
@@ -5958,6 +6121,14 @@ final class wire_cst_sdk_event extends ffi.Struct {
   external SdkEventKind kind;
 }
 
+final class wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser
+    extends ffi.Struct {
+  external ffi.Pointer<ffi.UintPtr> ptr;
+
+  @ffi.Int32()
+  external int len;
+}
+
 final class wire_cst_config extends ffi.Struct {
   external ffi.Pointer<wire_cst_list_prim_u_8_strict> liquid_electrum_url;
 
@@ -5981,6 +6152,10 @@ final class wire_cst_config extends ffi.Struct {
   external ffi.Pointer<ffi.Uint64> zero_conf_max_amount_sat;
 
   external ffi.Pointer<wire_cst_list_prim_u_8_strict> breez_api_key;
+
+  external ffi.Pointer<
+          wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser>
+      external_input_parsers;
 }
 
 final class wire_cst_connect_request extends ffi.Struct {
diff --git a/packages/dart/lib/src/lib.dart b/packages/dart/lib/src/lib.dart
index 2817799a..d593d844 100644
--- a/packages/dart/lib/src/lib.dart
+++ b/packages/dart/lib/src/lib.dart
@@ -6,5 +6,5 @@
 import 'frb_generated.dart';
 import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
 
-// Rust type: RustOpaqueNom<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<LNOfferBlindedPath>>
-abstract class LnOfferBlindedPath implements RustOpaqueInterface {}
+// Rust type: RustOpaqueNom<flutter_rust_bridge::for_generated::RustAutoOpaqueInner<ExternalInputParser>>
+abstract class ExternalInputParser implements RustOpaqueInterface {}
diff --git a/packages/dart/lib/src/model.dart b/packages/dart/lib/src/model.dart
index 3f17f444..3895a335 100644
--- a/packages/dart/lib/src/model.dart
+++ b/packages/dart/lib/src/model.dart
@@ -5,6 +5,7 @@
 
 import 'bindings.dart';
 import 'frb_generated.dart';
+import 'lib.dart';
 import 'package:flutter_rust_bridge/flutter_rust_bridge_for_generated.dart';
 import 'package:freezed_annotation/freezed_annotation.dart' hide protected;
 part 'model.freezed.dart';
@@ -141,6 +142,11 @@ class Config {
   /// The Breez API key used for making requests to their mempool service
   final String? breezApiKey;
 
+  /// A set of external input parsers that are used by [LiquidSdk::parse] when the input
+  /// is not recognized. See [ExternalInputParser] for more details on how to configure
+  /// external parsing.
+  final List<ExternalInputParser>? externalInputParsers;
+
   const Config({
     required this.liquidElectrumUrl,
     required this.bitcoinElectrumUrl,
@@ -152,6 +158,7 @@ class Config {
     required this.zeroConfMinFeeRateMsat,
     this.zeroConfMaxAmountSat,
     this.breezApiKey,
+    this.externalInputParsers,
   });
 
   @override
@@ -165,7 +172,8 @@ class Config {
       paymentTimeoutSec.hashCode ^
       zeroConfMinFeeRateMsat.hashCode ^
       zeroConfMaxAmountSat.hashCode ^
-      breezApiKey.hashCode;
+      breezApiKey.hashCode ^
+      externalInputParsers.hashCode;
 
   @override
   bool operator ==(Object other) =>
@@ -181,7 +189,8 @@ class Config {
           paymentTimeoutSec == other.paymentTimeoutSec &&
           zeroConfMinFeeRateMsat == other.zeroConfMinFeeRateMsat &&
           zeroConfMaxAmountSat == other.zeroConfMaxAmountSat &&
-          breezApiKey == other.breezApiKey;
+          breezApiKey == other.breezApiKey &&
+          externalInputParsers == other.externalInputParsers;
 }
 
 /// An argument when calling [crate::sdk::LiquidSdk::connect].
diff --git a/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart b/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart
index 7580437b..5942606a 100644
--- a/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart
+++ b/packages/flutter/lib/flutter_breez_liquid_bindings_generated.dart
@@ -347,6 +347,26 @@ class FlutterBreezLiquidBindings {
       _frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_lnurl_withdrawPtr
           .asFunction<void Function(int, int, ffi.Pointer<wire_cst_ln_url_withdraw_request>)>();
 
+  void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_parse(
+    int port_,
+    int that,
+    ffi.Pointer<wire_cst_list_prim_u_8_strict> input,
+  ) {
+    return _frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_parse(
+      port_,
+      that,
+      input,
+    );
+  }
+
+  late final _frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_parsePtr = _lookup<
+          ffi.NativeFunction<
+              ffi.Void Function(ffi.Int64, ffi.UintPtr, ffi.Pointer<wire_cst_list_prim_u_8_strict>)>>(
+      'frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_parse');
+  late final _frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_parse =
+      _frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_parsePtr
+          .asFunction<void Function(int, int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)>();
+
   void frbgen_breez_liquid_wire__crate__bindings__BindingLiquidSdk_pay_onchain(
     int port_,
     int that,
@@ -746,23 +766,6 @@ class FlutterBreezLiquidBindings {
       _frbgen_breez_liquid_wire__crate__bindings__default_configPtr
           .asFunction<WireSyncRust2DartDco Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)>();
 
-  void frbgen_breez_liquid_wire__crate__bindings__parse(
-    int port_,
-    ffi.Pointer<wire_cst_list_prim_u_8_strict> input,
-  ) {
-    return _frbgen_breez_liquid_wire__crate__bindings__parse(
-      port_,
-      input,
-    );
-  }
-
-  late final _frbgen_breez_liquid_wire__crate__bindings__parsePtr =
-      _lookup<ffi.NativeFunction<ffi.Void Function(ffi.Int64, ffi.Pointer<wire_cst_list_prim_u_8_strict>)>>(
-          'frbgen_breez_liquid_wire__crate__bindings__parse');
-  late final _frbgen_breez_liquid_wire__crate__bindings__parse =
-      _frbgen_breez_liquid_wire__crate__bindings__parsePtr
-          .asFunction<void Function(int, ffi.Pointer<wire_cst_list_prim_u_8_strict>)>();
-
   WireSyncRust2DartDco frbgen_breez_liquid_wire__crate__bindings__parse_invoice(
     ffi.Pointer<wire_cst_list_prim_u_8_strict> input,
   ) {
@@ -810,6 +813,38 @@ class FlutterBreezLiquidBindings {
       _frbgen_breez_liquid_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerBindingLiquidSdkPtr
           .asFunction<void Function(ffi.Pointer<ffi.Void>)>();
 
+  void
+      frbgen_breez_liquid_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+    ffi.Pointer<ffi.Void> ptr,
+  ) {
+    return _frbgen_breez_liquid_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+      ptr,
+    );
+  }
+
+  late final _frbgen_breez_liquid_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParserPtr =
+      _lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
+          'frbgen_breez_liquid_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser');
+  late final _frbgen_breez_liquid_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser =
+      _frbgen_breez_liquid_rust_arc_increment_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParserPtr
+          .asFunction<void Function(ffi.Pointer<ffi.Void>)>();
+
+  void
+      frbgen_breez_liquid_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+    ffi.Pointer<ffi.Void> ptr,
+  ) {
+    return _frbgen_breez_liquid_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+      ptr,
+    );
+  }
+
+  late final _frbgen_breez_liquid_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParserPtr =
+      _lookup<ffi.NativeFunction<ffi.Void Function(ffi.Pointer<ffi.Void>)>>(
+          'frbgen_breez_liquid_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser');
+  late final _frbgen_breez_liquid_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser =
+      _frbgen_breez_liquid_rust_arc_decrement_strong_count_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParserPtr
+          .asFunction<void Function(ffi.Pointer<ffi.Void>)>();
+
   ffi.Pointer<wire_cst_aes_success_action_data>
       frbgen_breez_liquid_cst_new_box_autoadd_aes_success_action_data() {
     return _frbgen_breez_liquid_cst_new_box_autoadd_aes_success_action_data();
@@ -1397,6 +1432,30 @@ class FlutterBreezLiquidBindings {
       _frbgen_breez_liquid_cst_new_box_autoadd_url_success_action_dataPtr
           .asFunction<ffi.Pointer<wire_cst_url_success_action_data> Function()>();
 
+  ffi.Pointer<
+          wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser>
+      frbgen_breez_liquid_cst_new_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+    int len,
+  ) {
+    return _frbgen_breez_liquid_cst_new_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser(
+      len,
+    );
+  }
+
+  late final _frbgen_breez_liquid_cst_new_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParserPtr =
+      _lookup<
+              ffi.NativeFunction<
+                  ffi.Pointer<
+                          wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser>
+                      Function(ffi.Int32)>>(
+          'frbgen_breez_liquid_cst_new_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser');
+  late final _frbgen_breez_liquid_cst_new_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser =
+      _frbgen_breez_liquid_cst_new_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParserPtr
+          .asFunction<
+              ffi.Pointer<
+                      wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser>
+                  Function(int)>();
+
   ffi.Pointer<wire_cst_list_String> frbgen_breez_liquid_cst_new_list_String(
     int len,
   ) {
@@ -4508,6 +4567,14 @@ final class wire_cst_sdk_event extends ffi.Struct {
   external SdkEventKind kind;
 }
 
+final class wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser
+    extends ffi.Struct {
+  external ffi.Pointer<ffi.UintPtr> ptr;
+
+  @ffi.Int32()
+  external int len;
+}
+
 final class wire_cst_config extends ffi.Struct {
   external ffi.Pointer<wire_cst_list_prim_u_8_strict> liquid_electrum_url;
 
@@ -4531,6 +4598,10 @@ final class wire_cst_config extends ffi.Struct {
   external ffi.Pointer<ffi.Uint64> zero_conf_max_amount_sat;
 
   external ffi.Pointer<wire_cst_list_prim_u_8_strict> breez_api_key;
+
+  external ffi.Pointer<
+          wire_cst_list_Auto_Owned_RustOpaque_flutter_rust_bridgefor_generatedRustAutoOpaqueInnerExternalInputParser>
+      external_input_parsers;
 }
 
 final class wire_cst_connect_request extends ffi.Struct {
diff --git a/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt b/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt
index 2959f6f6..a0e917e5 100644
--- a/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt
+++ b/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidMapper.kt
@@ -272,6 +272,14 @@ fun asConfig(config: ReadableMap): Config? {
         } else {
             null
         }
+    val externalInputParsers =
+        if (hasNonNullKey(config, "externalInputParsers")) {
+            config.getArray("externalInputParsers")?.let {
+                asExternalInputParserList(it)
+            }
+        } else {
+            null
+        }
     return Config(
         liquidElectrumUrl,
         bitcoinElectrumUrl,
@@ -283,6 +291,7 @@ fun asConfig(config: ReadableMap): Config? {
         breezApiKey,
         cacheDir,
         zeroConfMaxAmountSat,
+        externalInputParsers,
     )
 }
 
@@ -298,6 +307,7 @@ fun readableMapOf(config: Config): ReadableMap =
         "breezApiKey" to config.breezApiKey,
         "cacheDir" to config.cacheDir,
         "zeroConfMaxAmountSat" to config.zeroConfMaxAmountSat,
+        "externalInputParsers" to config.externalInputParsers?.let { readableArrayOf(it) },
     )
 
 fun asConfigList(arr: ReadableArray): List<Config> {
@@ -419,6 +429,42 @@ fun asCurrencyInfoList(arr: ReadableArray): List<CurrencyInfo> {
     return list
 }
 
+fun asExternalInputParser(externalInputParser: ReadableMap): ExternalInputParser? {
+    if (!validateMandatoryFields(
+            externalInputParser,
+            arrayOf(
+                "providerId",
+                "inputRegex",
+                "parserUrl",
+            ),
+        )
+    ) {
+        return null
+    }
+    val providerId = externalInputParser.getString("providerId")!!
+    val inputRegex = externalInputParser.getString("inputRegex")!!
+    val parserUrl = externalInputParser.getString("parserUrl")!!
+    return ExternalInputParser(providerId, inputRegex, parserUrl)
+}
+
+fun readableMapOf(externalInputParser: ExternalInputParser): ReadableMap =
+    readableMapOf(
+        "providerId" to externalInputParser.providerId,
+        "inputRegex" to externalInputParser.inputRegex,
+        "parserUrl" to externalInputParser.parserUrl,
+    )
+
+fun asExternalInputParserList(arr: ReadableArray): List<ExternalInputParser> {
+    val list = ArrayList<ExternalInputParser>()
+    for (value in arr.toList()) {
+        when (value) {
+            is ReadableMap -> list.add(asExternalInputParser(value)!!)
+            else -> throw SdkException.Generic(errUnexpectedType(value))
+        }
+    }
+    return list
+}
+
 fun asFiatCurrency(fiatCurrency: ReadableMap): FiatCurrency? {
     if (!validateMandatoryFields(
             fiatCurrency,
@@ -3291,6 +3337,7 @@ fun pushToArray(
 ) {
     when (value) {
         null -> array.pushNull()
+        is ExternalInputParser -> array.pushMap(readableMapOf(value))
         is FiatCurrency -> array.pushMap(readableMapOf(value))
         is LnOfferBlindedPath -> array.pushMap(readableMapOf(value))
         is LocaleOverrides -> array.pushMap(readableMapOf(value))
diff --git a/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidModule.kt b/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidModule.kt
index 6384862d..43f31b8c 100644
--- a/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidModule.kt
+++ b/packages/react-native/android/src/main/java/com/breezsdkliquid/BreezSDKLiquidModule.kt
@@ -75,21 +75,6 @@ class BreezSDKLiquidModule(
         }
     }
 
-    @ReactMethod
-    fun parse(
-        input: String,
-        promise: Promise,
-    ) {
-        executor.execute {
-            try {
-                val res = parse(input)
-                promise.resolve(readableMapOf(res))
-            } catch (e: Exception) {
-                promise.reject(e.javaClass.simpleName.replace("Exception", "Error"), e.message, e)
-            }
-        }
-    }
-
     @ReactMethod
     fun parseInvoice(
         input: String,
@@ -222,6 +207,21 @@ class BreezSDKLiquidModule(
         }
     }
 
+    @ReactMethod
+    fun parse(
+        input: String,
+        promise: Promise,
+    ) {
+        executor.execute {
+            try {
+                val res = getBindingLiquidSdk().parse(input)
+                promise.resolve(readableMapOf(res))
+            } catch (e: Exception) {
+                promise.reject(e.javaClass.simpleName.replace("Exception", "Error"), e.message, e)
+            }
+        }
+    }
+
     @ReactMethod
     fun prepareSendPayment(
         req: ReadableMap,
diff --git a/packages/react-native/ios/BreezSDKLiquidMapper.swift b/packages/react-native/ios/BreezSDKLiquidMapper.swift
index 12b0419a..3c832aeb 100644
--- a/packages/react-native/ios/BreezSDKLiquidMapper.swift
+++ b/packages/react-native/ios/BreezSDKLiquidMapper.swift
@@ -328,8 +328,12 @@ enum BreezSDKLiquidMapper {
             }
             zeroConfMaxAmountSat = zeroConfMaxAmountSatTmp
         }
+        var externalInputParsers: [ExternalInputParser]?
+        if let externalInputParsersTmp = config["externalInputParsers"] as? [[String: Any?]] {
+            externalInputParsers = try asExternalInputParserList(arr: externalInputParsersTmp)
+        }
 
-        return Config(liquidElectrumUrl: liquidElectrumUrl, bitcoinElectrumUrl: bitcoinElectrumUrl, mempoolspaceUrl: mempoolspaceUrl, workingDir: workingDir, network: network, paymentTimeoutSec: paymentTimeoutSec, zeroConfMinFeeRateMsat: zeroConfMinFeeRateMsat, breezApiKey: breezApiKey, cacheDir: cacheDir, zeroConfMaxAmountSat: zeroConfMaxAmountSat)
+        return Config(liquidElectrumUrl: liquidElectrumUrl, bitcoinElectrumUrl: bitcoinElectrumUrl, mempoolspaceUrl: mempoolspaceUrl, workingDir: workingDir, network: network, paymentTimeoutSec: paymentTimeoutSec, zeroConfMinFeeRateMsat: zeroConfMinFeeRateMsat, breezApiKey: breezApiKey, cacheDir: cacheDir, zeroConfMaxAmountSat: zeroConfMaxAmountSat, externalInputParsers: externalInputParsers)
     }
 
     static func dictionaryOf(config: Config) -> [String: Any?] {
@@ -344,6 +348,7 @@ enum BreezSDKLiquidMapper {
             "breezApiKey": config.breezApiKey == nil ? nil : config.breezApiKey,
             "cacheDir": config.cacheDir == nil ? nil : config.cacheDir,
             "zeroConfMaxAmountSat": config.zeroConfMaxAmountSat == nil ? nil : config.zeroConfMaxAmountSat,
+            "externalInputParsers": config.externalInputParsers == nil ? nil : arrayOf(externalInputParserList: config.externalInputParsers!),
         ]
     }
 
@@ -499,6 +504,45 @@ enum BreezSDKLiquidMapper {
         return currencyInfoList.map { v -> [String: Any?] in return dictionaryOf(currencyInfo: v) }
     }
 
+    static func asExternalInputParser(externalInputParser: [String: Any?]) throws -> ExternalInputParser {
+        guard let providerId = externalInputParser["providerId"] as? String else {
+            throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "providerId", typeName: "ExternalInputParser"))
+        }
+        guard let inputRegex = externalInputParser["inputRegex"] as? String else {
+            throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "inputRegex", typeName: "ExternalInputParser"))
+        }
+        guard let parserUrl = externalInputParser["parserUrl"] as? String else {
+            throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "parserUrl", typeName: "ExternalInputParser"))
+        }
+
+        return ExternalInputParser(providerId: providerId, inputRegex: inputRegex, parserUrl: parserUrl)
+    }
+
+    static func dictionaryOf(externalInputParser: ExternalInputParser) -> [String: Any?] {
+        return [
+            "providerId": externalInputParser.providerId,
+            "inputRegex": externalInputParser.inputRegex,
+            "parserUrl": externalInputParser.parserUrl,
+        ]
+    }
+
+    static func asExternalInputParserList(arr: [Any]) throws -> [ExternalInputParser] {
+        var list = [ExternalInputParser]()
+        for value in arr {
+            if let val = value as? [String: Any?] {
+                var externalInputParser = try asExternalInputParser(externalInputParser: val)
+                list.append(externalInputParser)
+            } else {
+                throw SdkError.Generic(message: errUnexpectedType(typeName: "ExternalInputParser"))
+            }
+        }
+        return list
+    }
+
+    static func arrayOf(externalInputParserList: [ExternalInputParser]) -> [Any] {
+        return externalInputParserList.map { v -> [String: Any?] in return dictionaryOf(externalInputParser: v) }
+    }
+
     static func asFiatCurrency(fiatCurrency: [String: Any?]) throws -> FiatCurrency {
         guard let id = fiatCurrency["id"] as? String else {
             throw SdkError.Generic(message: errMissingMandatoryField(fieldName: "id", typeName: "FiatCurrency"))
diff --git a/packages/react-native/ios/RNBreezSDKLiquid.m b/packages/react-native/ios/RNBreezSDKLiquid.m
index d92ea23e..b9640d45 100644
--- a/packages/react-native/ios/RNBreezSDKLiquid.m
+++ b/packages/react-native/ios/RNBreezSDKLiquid.m
@@ -10,12 +10,6 @@ @interface RCT_EXTERN_MODULE(RNBreezSDKLiquid, RCTEventEmitter)
     reject: (RCTPromiseRejectBlock)reject
 )
 
-RCT_EXTERN_METHOD(
-    parse: (NSString*)input
-    resolve: (RCTPromiseResolveBlock)resolve
-    reject: (RCTPromiseRejectBlock)reject
-)
-
 RCT_EXTERN_METHOD(
     parseInvoice: (NSString*)input
     resolve: (RCTPromiseResolveBlock)resolve
@@ -61,6 +55,12 @@ @interface RCT_EXTERN_MODULE(RNBreezSDKLiquid, RCTEventEmitter)
     reject: (RCTPromiseRejectBlock)reject
 )
 
+RCT_EXTERN_METHOD(
+    parse: (NSString*)input
+    resolve: (RCTPromiseResolveBlock)resolve
+    reject: (RCTPromiseRejectBlock)reject
+)
+
 RCT_EXTERN_METHOD(
     prepareSendPayment: (NSDictionary*)req
     resolve: (RCTPromiseResolveBlock)resolve
diff --git a/packages/react-native/ios/RNBreezSDKLiquid.swift b/packages/react-native/ios/RNBreezSDKLiquid.swift
index 11b484f8..7dc00200 100644
--- a/packages/react-native/ios/RNBreezSDKLiquid.swift
+++ b/packages/react-native/ios/RNBreezSDKLiquid.swift
@@ -84,16 +84,6 @@ class RNBreezSDKLiquid: RCTEventEmitter {
         }
     }
 
-    @objc(parse:resolve:reject:)
-    func parse(_ input: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
-        do {
-            var res = try BreezSDKLiquid.parse(input: input)
-            resolve(BreezSDKLiquidMapper.dictionaryOf(inputType: res))
-        } catch let err {
-            rejectErr(err: err, reject: reject)
-        }
-    }
-
     @objc(parseInvoice:resolve:reject:)
     func parseInvoice(_ input: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
         do {
@@ -187,6 +177,16 @@ class RNBreezSDKLiquid: RCTEventEmitter {
         }
     }
 
+    @objc(parse:resolve:reject:)
+    func parse(_ input: String, resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
+        do {
+            var res = try getBindingLiquidSdk().parse(input: input)
+            resolve(BreezSDKLiquidMapper.dictionaryOf(inputType: res))
+        } catch let err {
+            rejectErr(err: err, reject: reject)
+        }
+    }
+
     @objc(prepareSendPayment:resolve:reject:)
     func prepareSendPayment(_ req: [String: Any], resolve: @escaping RCTPromiseResolveBlock, reject: @escaping RCTPromiseRejectBlock) {
         do {
diff --git a/packages/react-native/src/index.ts b/packages/react-native/src/index.ts
index 23d8c854..1db41a0f 100644
--- a/packages/react-native/src/index.ts
+++ b/packages/react-native/src/index.ts
@@ -68,6 +68,7 @@ export interface Config {
     breezApiKey?: string
     cacheDir?: string
     zeroConfMaxAmountSat?: number
+    externalInputParsers?: ExternalInputParser[]
 }
 
 export interface ConnectRequest {
@@ -89,6 +90,12 @@ export interface CurrencyInfo {
     localeOverrides: LocaleOverrides[]
 }
 
+export interface ExternalInputParser {
+    providerId: string
+    inputRegex: string
+    parserUrl: string
+}
+
 export interface FiatCurrency {
     id: string
     info: CurrencyInfo
@@ -747,11 +754,6 @@ export const defaultConfig = async (network: LiquidNetwork, breezApiKey: string
     return response
 }
 
-export const parse = async (input: string): Promise<InputType> => {
-    const response = await BreezSDKLiquid.parse(input)
-    return response
-}
-
 export const parseInvoice = async (input: string): Promise<LnInvoice> => {
     const response = await BreezSDKLiquid.parseInvoice(input)
     return response
@@ -777,6 +779,11 @@ export const checkMessage = async (req: CheckMessageRequest): Promise<CheckMessa
     return response
 }
 
+export const parse = async (input: string): Promise<InputType> => {
+    const response = await BreezSDKLiquid.parse(input)
+    return response
+}
+
 export const prepareSendPayment = async (req: PrepareSendRequest): Promise<PrepareSendResponse> => {
     const response = await BreezSDKLiquid.prepareSendPayment(req)
     return response


Test patch:
diff --git a/lib/core/src/test_utils/swapper.rs b/lib/core/src/test_utils/swapper.rs
index 68c35517..322568dc 100644
--- a/lib/core/src/test_utils/swapper.rs
+++ b/lib/core/src/test_utils/swapper.rs
@@ -314,7 +314,7 @@ impl Swapper for MockSwapper {
         unimplemented!()
     }
 
-    fn get_zero_amount_chain_swap_quote(&self, swap_id: &str) -> Result<Amount, PaymentError> {
+    fn get_zero_amount_chain_swap_quote(&self, _swap_id: &str) -> Result<Amount, PaymentError> {
         unimplemented!()
     }