Keyboard shortcuts

Press โ† or โ†’ to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

SDK Documentation Spark
Request API Key

Routing traffic through a SOCKS5 proxy

Set proxyproxyproxyproxyproxyproxyproxyProxyProxy on the config to send the connections the SDK opens through a SOCKS5 proxy, such as a local Tor daemon.

Rust
let mut config = default_config(Network::Mainnet);
config.api_key = Some("<breez api key>".to_string());

// Route the SDK's connections through a SOCKS5 proxy, such as a local Tor
// daemon. Set username and password together for proxies that require
// RFC 1929 authentication.
config.proxy = Some(ProxyConfig {
    host: "127.0.0.1".to_string(),
    port: 9050,
    username: None,
    password: None,
});
Swift
var config = defaultConfig(network: Network.mainnet)
config.apiKey = "<breez api key>"

// Route the SDK's connections through a SOCKS5 proxy, such as a local Tor
// daemon. Set username and password together for proxies that require
// RFC 1929 authentication.
config.proxy = ProxyConfig(
    host: "127.0.0.1",
    port: 9050,
    username: nil,
    password: nil
)
Kotlin
val config = defaultConfig(Network.MAINNET)
config.apiKey = "<breez api key>"

// Route the SDK's connections through a SOCKS5 proxy, such as a local Tor
// daemon. Set username and password together for proxies that require
// RFC 1929 authentication.
config.proxy = ProxyConfig(
    host = "127.0.0.1",
    port = 9050u,
    username = null,
    password = null,
)
C#
// Route the SDK's connections through a SOCKS5 proxy, such as a local
// Tor daemon. Set username and password together for proxies that
// require RFC 1929 authentication.
var config = BreezSdkSparkMethods.DefaultConfig(Network.Mainnet) with
{
    apiKey = "<breez api key>",
    proxy = new ProxyConfig(
        host: "127.0.0.1",
        port: 9050,
        username: null,
        password: null)
};
React Native
const config = defaultConfig(Network.Mainnet)
config.apiKey = '<breez api key>'

// Route the SDK's connections through a SOCKS5 proxy, such as a local Tor
// daemon. Set username and password together for proxies that require
// RFC 1929 authentication.
config.proxy = {
  host: '127.0.0.1',
  port: 9050,
  username: undefined,
  password: undefined
}
Flutter
// Route the SDK's connections through a SOCKS5 proxy, such as a local Tor
// daemon. Set username and password together for proxies that require
// RFC 1929 authentication.
final config = defaultConfig(network: Network.mainnet).copyWith(
  apiKey: "<breez api key>",
  proxy: const ProxyConfig(
    host: "127.0.0.1",
    port: 9050,
    username: null,
    password: null,
  ),
);
Python
config = default_config(network=Network.MAINNET)
config.api_key = "<breez api key>"

# Route the SDK's connections through a SOCKS5 proxy, such as a local Tor
# daemon. Set username and password together for proxies that require
# RFC 1929 authentication.
config.proxy = ProxyConfig(
    host="127.0.0.1",
    port=9050,
    username=None,
    password=None,
)
Go
config := breez_sdk_spark.DefaultConfig(breez_sdk_spark.NetworkMainnet)
apiKey := "<breez api key>"
config.ApiKey = &apiKey

// Route the SDK's connections through a SOCKS5 proxy, such as a local Tor
// daemon. Set username and password together for proxies that require
// RFC 1929 authentication.
config.Proxy = &breez_sdk_spark.ProxyConfig{
	Host:     "127.0.0.1",
	Port:     9050,
	Username: nil,
	Password: nil,
}

Set usernameusernameusernameusernameusernameusernameusernameUsernameUsername and passwordpasswordpasswordpasswordpasswordpasswordpasswordPasswordPassword together for proxies that require RFC 1929 authentication. Setting only one of them is rejected.

What the proxy covers

Every connection the SDK opens, HTTP and gRPC alike.

Hostnames are resolved by the proxy, never locally, so no DNS query reveals which host you are reaching. BIP353 name lookups switch from plain DNS to DNS-over-HTTPS for the same reason: plain DNS is UDP, which a SOCKS5 proxy does not carry, so those queries would otherwise escape the tunnel. They stay DNSSEC-verified either way.

Only the proxy's own address is resolved locally, which is unavoidable: it is the one host that cannot be reached through itself.

Failing closed

A connection that cannot be established through the proxy fails. The SDK never retries it directly, and setting a proxy also disables system-proxy autodetection, so no environment variable can route traffic around it.

A configuration the SDK cannot honour is rejected where it is supplied, rather than partly applied: at connectconnectconnectconnectconnectconnectconnectConnectConnect, or at the constructor of a component built outside the SDK.

Rejected combinationWhy
A proxy on WASMThe browser owns connection setup and exposes no proxy control.
proxyproxyproxyproxyproxyproxyproxyProxyProxy with connections_per_operatorconnections_per_operatorconnectionsPerOperatorconnectionsPerOperatorconnectionsPerOperatorconnectionsPerOperatorconnectionsPerOperatorConnectionsPerOperatorConnectionsPerOperator above 1Balanced operator connections build their own connectors and cannot be routed.
A proxy carrying credentials on PasskeyConfigPasskeyConfigPasskeyConfigPasskeyConfigPasskeyConfigPasskeyConfigPasskeyConfigPasskeyConfigPasskeyConfigNostr relay connections cannot authenticate to a proxy. Wallet labels live on those relays and are one of the salts a wallet seed derives from, so a label that cannot be published cannot be recovered: this fails before a wallet exists rather than after one is funded.

Shared SDK Context

A shared SDK Context owns the pooled HTTP client and gRPC channels, so the proxy has to be set on SdkContextConfigSdkContextConfigSdkContextConfigSdkContextConfigSdkContextConfigSdkContextConfigSdkContextConfigSdkContextConfigSdkContextConfig as well. It must match the proxyproxyproxyproxyproxyproxyproxyProxyProxy on the ConfigConfigConfigConfigConfigConfigConfigConfigConfig of every SDK built from that context: the SDK rejects a mismatch at connectconnectconnectconnectconnectconnectconnectConnectConnect, since a disagreement would mean part of the traffic bypassed the proxy.

Components built outside the SDK

A few APIs run without an SDK instance, so they cannot pick the setting up on their own. Pass the same proxy to each one you use:

  • get_spark_statusget_spark_statusgetSparkStatusgetSparkStatusgetSparkStatusgetSparkStatusgetSparkStatusGetSparkStatusGetSparkStatus, via GetSparkStatusRequestGetSparkStatusRequestGetSparkStatusRequestGetSparkStatusRequestGetSparkStatusRequestGetSparkStatusRequestGetSparkStatusRequestGetSparkStatusRequestGetSparkStatusRequest
  • new_rest_chain_servicenew_rest_chain_servicenewRestChainServicenewRestChainServicenewRestChainServicenewRestChainServicenewRestChainServiceNewRestChainServiceNewRestChainService, via NewRestChainServiceRequestNewRestChainServiceRequestNewRestChainServiceRequestNewRestChainServiceRequestNewRestChainServiceRequestNewRestChainServiceRequestNewRestChainServiceRequestNewRestChainServiceRequestNewRestChainServiceRequest
  • The Turnkey signer, via TurnkeyConfigTurnkeyConfigTurnkeyConfigTurnkeyConfigTurnkeyConfigTurnkeyConfigTurnkeyConfigTurnkeyConfigTurnkeyConfig
  • The passkey client, via PasskeyConfigPasskeyConfigPasskeyConfigPasskeyConfigPasskeyConfigPasskeyConfigPasskeyConfigPasskeyConfigPasskeyConfig. A proxy carrying credentials is rejected when the client is constructed (see above).

A service you supply yourself through with_chain_servicewith_chain_servicewithChainServicewithChainServicewithChainServicewithChainServicewithChainServiceWithChainServiceWithChainService, with_fiat_servicewith_fiat_servicewithFiatServicewithFiatServicewithFiatServicewithFiatServicewithFiatServiceWithFiatServiceWithFiatService, with_lnurl_clientwith_lnurl_clientwithLnurlClientwithLnurlClientwithLnurlClientwithLnurlClientwithLnurlClientWithLnurlClientWithLnurlClient or with_lnurl_server_clientwith_lnurl_server_clientwithLnurlServerClientwithLnurlServerClientwithLnurlServerClientwithLnurlServerClientwithLnurlServerClientWithLnurlServerClientWithLnurlServerClient already owns its transport, which the SDK cannot inspect or re-route. Make it connect through the proxy yourself; the SDK logs a warning when it sees one alongside a proxy. with_rest_chain_servicewith_rest_chain_servicewithRestChainServicewithRestChainServicewithRestChainServicewithRestChainServicewithRestChainServiceWithRestChainServiceWithRestChainService is built on the SDK's own client and is proxied automatically.

JavaScript and WASM

A SOCKS5 proxy cannot be honoured in a browser, and setting proxyproxyproxyproxyproxyproxyproxyProxyProxy on a WASM build is an error rather than a silent direct connection.

In Node, route the SDK by installing a proxy dispatcher on the global fetch before connecting, which covers both the HTTP and gRPC calls the WASM build makes:

import { setGlobalDispatcher, ProxyAgent } from 'undici'

setGlobalDispatcher(new ProxyAgent('socks5://127.0.0.1:9050'))