Customizing the SDK
Using the SDK Builder gives you more control over the initialization and modular components used when the SDK is running. Below you can find examples of initializing the SDK using the SDK Builder and implementing modular components:
- Storage to manage stored data
- PostgreSQL Connection Pool as an alternative storage backend
- MySQL Connection Pool as an alternative storage backend
- Bitcoin Chain Service to provide network data
- Shared REST Chain Service to share the chain service HTTP client across SDK instances
- LNURL Client to make REST requests
- Fiat Service to provide Fiat currencies and exchange rates
- Change the Key Set to alter the derivation path used
- Payment Observer to be notified before payments occur
- SSP Connection Manager to share the SSP HTTP client across SDK instances
- Connection Manager to share gRPC connections across SDK instances
// Construct the seed using a mnemonic, entropy or passkey
let mnemonic = "<mnemonic words>".to_string();
let seed = Seed::Mnemonic {
mnemonic,
passphrase: None,
};
// Create the default config
let mut config = default_config(Network::Mainnet);
config.api_key = Some("<breez api key>".to_string());
// Build the SDK using the config, seed and default storage
let builder = SdkBuilder::new(config, seed).with_default_storage("./.data".to_string());
// You can also pass your custom implementations:
// let builder = builder.with_storage(<your storage implementation>)
// let builder = builder.with_chain_service(<your chain service implementation>)
// let builder = builder.with_rest_client(<your rest client implementation>)
// let builder = builder.with_key_set(KeySetConfig { key_set_type: <your key set type>, use_address_index: <use address index>, account_number: <account number> })
// let builder = builder.with_payment_observer(<your payment observer implementation>);
let sdk = builder.build().await?;
// Construct the seed using a mnemonic, entropy or passkey
let mnemonic = "<mnemonic words>"
let seed = Seed.mnemonic(mnemonic: mnemonic, passphrase: nil)
// Create the default config
var config = defaultConfig(network: Network.mainnet)
config.apiKey = "<breez api key>"
// Build the SDK using the config, seed and default storage
let builder = SdkBuilder(config: config, seed: seed)
await builder.withDefaultStorage(storageDir: "./.data")
// You can also pass your custom implementations:
// await builder.withStorage(<your storage implementation>)
// await builder.withChainService(<your chain service implementation>)
// await builder.withRestClient(<your rest client implementation>)
// await builder.withKeySet(<your key set type>, <use address index>, <account number>)
// await builder.withPaymentObserver(<your payment observer implementation>)
let sdk = try await builder.build()
// Construct the seed using a mnemonic, entropy or passkey
val mnemonic = "<mnemonic words>"
val seed = Seed.Mnemonic(mnemonic, null)
// Create the default config
val config = defaultConfig(Network.MAINNET)
config.apiKey = "<breez api key>"
try {
// Build the SDK using the config, seed and default storage
val builder = SdkBuilder(config, seed)
builder.withDefaultStorage("./.data")
// You can also pass your custom implementations:
// builder.withStorage(<your storage implementation>)
// builder.withChainService(<your chain service implementation>)
// builder.withRestClient(<your rest client implementation>)
// builder.withKeySet(<your key set type>, <use address index>, <account number>)
// builder.withPaymentObserver(<your payment observer implementation>)
val sdk = builder.build()
} catch (e: Exception) {
// handle error
}
// Construct the seed using a mnemonic, entropy or passkey
var mnemonic = "<mnemonic words>";
var seed = new Seed.Mnemonic(mnemonic: mnemonic, passphrase: null);
// Create the default config
var config = BreezSdkSparkMethods.DefaultConfig(Network.Mainnet) with
{
apiKey = "<breez api key>"
};
// Build the SDK using the config, seed and default storage
var builder = new SdkBuilder(config: config, seed: seed);
await builder.WithDefaultStorage(storageDir: "./.data");
// You can also pass your custom implementations:
// await builder.WithStorage(<your storage implementation>)
// await builder.WithChainService(<your chain service implementation>)
// await builder.WithRestClient(<your rest client implementation>)
// await builder.WithKeySet(<your key set type>, <use address index>, <account number>)
// await builder.WithPaymentObserver(<your payment observer implementation>);
var sdk = await builder.Build();
// Call init when using the SDK in a web environment before calling any other SDK
// methods. This is not needed when using the SDK in a Node.js/Deno environment.
await init()
// Construct the seed using a mnemonic, entropy or passkey
const mnemonic = '<mnemonic words>'
const seed: Seed = { type: 'mnemonic', mnemonic, passphrase: undefined }
// Create the default config
const config = defaultConfig('mainnet')
config.apiKey = '<breez api key>'
// Build the SDK using the config, seed and default storage
let builder = SdkBuilder.new(config, seed)
builder = await builder.withDefaultStorage('./.data')
// You can also pass your custom implementations:
// builder = builder.withStorage(<your storage implementation>)
// builder = builder.withChainService(<your chain service implementation>)
// builder = builder.withRestClient(<your rest client implementation>)
// builder = builder.withKeySet({ keySetType: <your key set type>, useAddressIndex: <use address index>, accountNumber: <account number> })
// builder = builder.withPaymentObserver(<your payment observer implementation>)
const sdk = await builder.build()
// Construct the seed using a mnemonic, entropy or passkey
const mnemonic = '<mnemonics words>'
const seed = new Seed.Mnemonic({ mnemonic, passphrase: undefined })
// Create the default config
const config = defaultConfig(Network.Mainnet)
config.apiKey = '<breez api key>'
// Build the SDK using the config, seed and default storage
const builder = new SdkBuilder(config, seed)
await builder.withDefaultStorage(`${RNFS.DocumentDirectoryPath}/data`)
// You can also pass your custom implementations:
// await builder.withStorage(<your storage implementation>)
// await builder.withChainService(<your chain service implementation>)
// await builder.withRestClient(<your rest client implementation>)
// await builder.withKeySet({ keySetType: <your key set type>, useAddressIndex: <use address index>, accountNumber: <account number> })
// await builder.withPaymentObserver(<your payment observer implementation>)
const sdk = await builder.build()
// Construct the seed using a mnemonic, entropy or passkey
String mnemonic = "<mnemonic words>";
final seed = Seed.mnemonic(mnemonic: mnemonic, passphrase: null);
// Create the default config
final config = defaultConfig(network: Network.mainnet)
.copyWith(apiKey: "<breez api key>");
// Build the SDK using the config, seed and default storage
final builder = SdkBuilder(config: config, seed: seed);
builder.withDefaultStorage(storageDir: "./.data");
// You can also pass your custom implementations:
// builder.withRestChainService(
// url: "https://custom.chain.service",
// credentials: Credentials(
// username: "service-username", password: "service-password"));
// builder.withKeySet(config: KeySetConfig(keySetType: <your key set type>, useAddressIndex: <use address index>, accountNumber: <account number>));
final sdk = await builder.build();
# Construct the seed using a mnemonic, entropy or passkey
mnemonic = "<mnemonic words>"
seed = Seed.MNEMONIC(mnemonic=mnemonic, passphrase=None)
# Create the default config
config = default_config(network=Network.MAINNET)
config.api_key = "<breez api key>"
try:
# Build the SDK using the config, seed and default storage
builder = SdkBuilder(config=config, seed=seed)
await builder.with_default_storage(storage_dir="./.data")
# You can also pass your custom implementations:
# await builder.with_storage(<your storage implementation>)
# await builder.with_chain_service(<your chain service implementation>)
# await builder.with_rest_client(<your rest client implementation>)
# await builder.with_key_set(<your key set type>, <use address index>, <account number>)
# await builder.with_payment_observer(<your payment observer implementation>)
sdk = await builder.build()
return sdk
except Exception as error:
logging.error(error)
raise
// Construct the seed using a mnemonic, entropy or passkey
mnemonic := "<mnemonic words>"
var seed breez_sdk_spark.Seed = breez_sdk_spark.SeedMnemonic{
Mnemonic: mnemonic,
Passphrase: nil,
}
// Create the default config
apiKey := "<breez api key>"
config := breez_sdk_spark.DefaultConfig(breez_sdk_spark.NetworkMainnet)
config.ApiKey = &apiKey
// Build the SDK using the config, seed and default storage
builder := breez_sdk_spark.NewSdkBuilder(config, seed)
builder.WithDefaultStorage("./.data")
// You can also pass your custom implementations:
// builder.WithStorage(<your storage implementation>)
// builder.WithChainService(<your chain service implementation>)
// builder.WithRestClient(<your rest client implementation>)
// builder.WithKeySet(<your key set type>, <use address index>, <account number>)
// builder.WithPaymentObserver(<your payment observer implementation>)
sdk, err := builder.Build()
return sdk, err
With Storage API docs
When using the SDK Builder, you either have to provide a Storage implementation or use the default storage from the SDK.
Note: Flutter currently only supports using the default storage.
With PostgreSQL Connection Pool API docs
The SDK includes a PostgreSQL backend as an alternative to file-based storage. Construct a connection pool once with create_postgres_connection_poolcreate_postgres_connection_poolcreatePostgresConnectionPoolcreatePostgresConnectionPoolcreatePostgresConnectionPoolcreatePostgresConnectionPoolcreatePostgresConnectionPoolCreatePostgresConnectionPoolCreatePostgresConnectionPool and pass it to the builder via with_postgres_connection_poolwith_postgres_connection_poolwithPostgresConnectionPoolwithPostgresConnectionPoolwithPostgresConnectionPoolwithPostgresConnectionPoolwithPostgresConnectionPoolWithPostgresConnectionPoolWithPostgresConnectionPool — this configures PostgreSQL for all stores (storage, tree store, and token store), which is suitable for server-side deployments with horizontal scaling. The same pool can be shared across multiple SdkBuilder instances; per-tenant scoping (rows isolated by seed identity) is preserved.
If your service owns the database schema and applies SDK-compatible migrations externally, set run_migrationrun_migrationrunMigrationrunMigrationrunMigrationrunMigrationrunMigrationRunMigrationRunMigration to false on the storage config before creating the pool. The SDK will trust the existing schema and skip all migration runs, including writes to schema migration tables.
Note: Not available for React Native or Flutter. For JavaScript/TypeScript, only supported in Node.js (not in the browser).
// Construct the seed using a mnemonic, entropy or passkey
let mnemonic = "<mnemonic words>".to_string();
let seed = Seed::Mnemonic {
mnemonic,
passphrase: None,
};
// Create the default config
let mut config = default_config(Network::Mainnet);
config.api_key = Some("<breez api key>".to_string());
// Configure PostgreSQL backend
// Connection string format: "host=localhost user=postgres password=secret dbname=spark"
// Or URI format: "postgres://user:password@host:port/dbname?sslmode=require"
let mut postgres_config =
default_postgres_storage_config("host=localhost user=postgres dbname=spark".to_string());
// Optionally pool settings can be adjusted. Some examples:
postgres_config.max_pool_size = 8; // Max connections in pool
postgres_config.wait_timeout_secs = Some(30); // Timeout waiting for connection
// If your service owns SDK-compatible schema migrations:
postgres_config.run_migration = false;
// Construct the connection pool. The same `Arc<PostgresConnectionPool>`
// can be passed to multiple SdkBuilders to share connections across SDKs;
// per-tenant scoping (rows isolated by seed identity) is preserved.
let pool = create_postgres_connection_pool(&postgres_config)?;
// Build the SDK with PostgreSQL backend (storage, tree store, and token store)
let sdk = SdkBuilder::new(config, seed)
.with_postgres_connection_pool(pool)
.build()
.await?;
// Construct the seed using a mnemonic, entropy or passkey
let mnemonic = "<mnemonic words>"
let seed = Seed.mnemonic(mnemonic: mnemonic, passphrase: nil)
// Create the default config
var config = defaultConfig(network: Network.mainnet)
config.apiKey = "<breez api key>"
// Configure PostgreSQL backend
// Connection string format: "host=localhost user=postgres password=secret dbname=spark"
// Or URI format: "postgres://user:password@host:port/dbname?sslmode=require"
var postgresConfig = defaultPostgresStorageConfig(
connectionString: "host=localhost user=postgres dbname=spark"
)
// Optionally pool settings can be adjusted. Some examples:
postgresConfig.maxPoolSize = UInt32(8) // Max connections in pool
postgresConfig.waitTimeoutSecs = UInt64(30) // Timeout waiting for connection
// If your service owns SDK-compatible schema migrations:
postgresConfig.runMigration = false
// Construct the connection pool. The same pool can be passed to
// multiple SdkBuilders to share connections across SDKs; per-tenant
// scoping (rows isolated by seed identity) is preserved.
let pool = try createPostgresConnectionPool(config: postgresConfig)
// Build the SDK with PostgreSQL backend (storage, tree store, and token store)
let builder = SdkBuilder(config: config, seed: seed)
await builder.withPostgresConnectionPool(pool: pool)
let sdk = try await builder.build()
// Construct the seed using a mnemonic, entropy or passkey
val mnemonic = "<mnemonic words>"
val seed = Seed.Mnemonic(mnemonic, null)
// Create the default config
val config = defaultConfig(Network.MAINNET)
config.apiKey = "<breez api key>"
// Configure PostgreSQL backend
// Connection string format: "host=localhost user=postgres password=secret dbname=spark"
// Or URI format: "postgres://user:password@host:port/dbname?sslmode=require"
val postgresConfig = defaultPostgresStorageConfig("host=localhost user=postgres dbname=spark")
// Optionally pool settings can be adjusted. Some examples:
postgresConfig.maxPoolSize = 8u // Max connections in pool
postgresConfig.waitTimeoutSecs = 30u // Timeout waiting for connection
// If your service owns SDK-compatible schema migrations:
postgresConfig.runMigration = false
// Construct the connection pool. The same pool can be passed to
// multiple SdkBuilders to share connections across SDKs; per-tenant
// scoping (rows isolated by seed identity) is preserved.
val pool = createPostgresConnectionPool(postgresConfig)
try {
// Build the SDK with PostgreSQL backend (storage, tree store, and token store)
val builder = SdkBuilder(config, seed)
builder.withPostgresConnectionPool(pool)
val sdk = builder.build()
} catch (e: Exception) {
// handle error
}
// Construct the seed using a mnemonic, entropy or passkey
var mnemonic = "<mnemonic words>";
var seed = new Seed.Mnemonic(mnemonic: mnemonic, passphrase: null);
// Create the default config
var config = BreezSdkSparkMethods.DefaultConfig(Network.Mainnet) with
{
apiKey = "<breez api key>"
};
// Configure PostgreSQL backend
// Connection string format: "host=localhost user=postgres password=secret dbname=spark"
// Or URI format: "postgres://user:password@host:port/dbname?sslmode=require"
var postgresConfig = BreezSdkSparkMethods.DefaultPostgresStorageConfig(
connectionString: "host=localhost user=postgres dbname=spark"
);
// Optionally pool settings can be adjusted. Some examples:
postgresConfig = postgresConfig with
{
maxPoolSize = 8u, // Max connections in pool
waitTimeoutSecs = 30ul, // Timeout waiting for connection
// If your service owns SDK-compatible schema migrations:
runMigration = false
};
// Construct the connection pool. The same pool can be passed to
// multiple SdkBuilders to share connections across SDKs; per-tenant
// scoping (rows isolated by seed identity) is preserved.
var pool = BreezSdkSparkMethods.CreatePostgresConnectionPool(config: postgresConfig);
// Build the SDK with PostgreSQL backend (storage, tree store, and token store)
var builder = new SdkBuilder(config: config, seed: seed);
await builder.WithPostgresConnectionPool(pool: pool);
var sdk = await builder.Build();
// Construct the seed using a mnemonic, entropy or passkey
const mnemonic = '<mnemonic words>'
const seed: Seed = { type: 'mnemonic', mnemonic, passphrase: undefined }
// Create the default config
const config = defaultConfig('mainnet')
config.apiKey = '<breez api key>'
// Configure PostgreSQL backend
// Connection string format: "host=localhost user=postgres password=secret dbname=spark"
// Or URI format: "postgres://user:password@host:port/dbname?sslmode=require"
const pgConfig = defaultPostgresStorageConfig('host=localhost user=postgres dbname=spark')
// Optionally pool settings can be adjusted. Some examples:
pgConfig.maxPoolSize = 8 // Max connections in pool
pgConfig.createTimeoutSecs = 30 // Timeout for establishing a new connection
pgConfig.recycleTimeoutSecs = 30 // Timeout for recycling an idle connection
// If your service owns SDK-compatible schema migrations:
pgConfig.runMigration = false
// Construct the connection pool. The same pool handle can be passed to
// multiple SdkBuilders to share connections across SDKs; per-tenant
// scoping (rows isolated by seed identity) is preserved.
const pool = createPostgresConnectionPool(pgConfig)
// Build the SDK with PostgreSQL backend (storage, tree store, and token store)
let builder = SdkBuilder.new(config, seed)
builder = builder.withPostgresConnectionPool(pool)
const sdk = await builder.build()
async def init_sdk_postgres():
# Construct the seed using a mnemonic, entropy or passkey
mnemonic = "<mnemonic words>"
seed = Seed.MNEMONIC(mnemonic=mnemonic, passphrase=None)
# Create the default config
config = default_config(network=Network.MAINNET)
config.api_key = "<breez api key>"
# Configure PostgreSQL storage
# Connection string format: "host=localhost user=postgres password=secret dbname=spark"
# Or URI format: "postgres://user:password@host:port/dbname?sslmode=require"
postgres_config = default_postgres_storage_config(
connection_string="host=localhost user=postgres dbname=spark"
)
# Optionally pool settings can be adjusted. Some examples:
postgres_config.max_pool_size = 8 # Max connections in pool
postgres_config.wait_timeout_secs = 30 # Timeout waiting for connection
# If your service owns SDK-compatible schema migrations:
postgres_config.run_migration = False
# Construct the connection pool. The same pool can be passed to multiple
# SdkBuilders to share connections across SDKs; per-tenant scoping (rows
# isolated by seed identity) is preserved.
pool = create_postgres_connection_pool(config=postgres_config)
try:
# Build the SDK with PostgreSQL backend (storage, tree store, and token store)
builder = SdkBuilder(config=config, seed=seed)
await builder.with_postgres_connection_pool(pool=pool)
sdk = await builder.build()
return sdk
except Exception as error:
logging.error(error)
raise
// Construct the seed using a mnemonic, entropy or passkey
mnemonic := "<mnemonic words>"
var seed breez_sdk_spark.Seed = breez_sdk_spark.SeedMnemonic{
Mnemonic: mnemonic,
Passphrase: nil,
}
// Create the default config
apiKey := "<breez api key>"
config := breez_sdk_spark.DefaultConfig(breez_sdk_spark.NetworkMainnet)
config.ApiKey = &apiKey
// Configure PostgreSQL backend
// Connection string format: "host=localhost user=postgres password=secret dbname=spark"
// Or URI format: "postgres://user:password@host:port/dbname?sslmode=require"
postgresConfig := breez_sdk_spark.DefaultPostgresStorageConfig("host=localhost user=postgres dbname=spark")
// Optionally pool settings can be adjusted. Some examples:
postgresConfig.MaxPoolSize = 8 // Max connections in pool
waitTimeoutSecs := uint64(30)
postgresConfig.WaitTimeoutSecs = &waitTimeoutSecs // Timeout waiting for connection
// If your service owns SDK-compatible schema migrations:
postgresConfig.RunMigration = false
// Construct the connection pool. The same pool can be passed to multiple
// SdkBuilders to share connections across SDKs; per-tenant scoping (rows
// isolated by seed identity) is preserved.
pool, err := breez_sdk_spark.CreatePostgresConnectionPool(postgresConfig)
if err != nil {
return nil, err
}
// Build the SDK with PostgreSQL backend (storage, tree store, and token store)
builder := breez_sdk_spark.NewSdkBuilder(config, seed)
builder.WithPostgresConnectionPool(pool)
sdk, err := builder.Build()
if err != nil {
return nil, err
}
Developer note
Sharing the same PostgreSQL database with multiple SDK instances is incompatible with real-time sync. See Real-time sync server URL for how to disable it.
The PostgreSQL tree store can use the same or a separate PostgreSQL database as the PostgreSQL storage. The tree store uses its own set of tables prefixed with tree_.
With MySQL Connection Pool API docs
The SDK includes a MySQL backend (MySQL 8.0+) as an alternative to file-based storage. Construct a connection pool once with create_mysql_connection_poolcreate_mysql_connection_poolcreateMysqlConnectionPoolcreateMysqlConnectionPoolcreateMysqlConnectionPoolcreateMysqlConnectionPoolcreateMysqlConnectionPoolCreateMysqlConnectionPoolCreateMysqlConnectionPool and pass it to the builder via with_mysql_connection_poolwith_mysql_connection_poolwithMysqlConnectionPoolwithMysqlConnectionPoolwithMysqlConnectionPoolwithMysqlConnectionPoolwithMysqlConnectionPoolWithMysqlConnectionPoolWithMysqlConnectionPool — this configures MySQL for all stores (storage, tree store, and token store), which is suitable for server-side deployments with horizontal scaling. The same pool can be shared across multiple SdkBuilder instances; per-tenant scoping (rows isolated by seed identity) is preserved.
If your service owns the database schema and applies SDK-compatible migrations externally, set run_migrationrun_migrationrunMigrationrunMigrationrunMigrationrunMigrationrunMigrationRunMigrationRunMigration to false on the storage config before creating the pool. The SDK will trust the existing schema and skip all migration runs, including writes to schema migration tables.
Note: Not available for React Native or Flutter. For JavaScript/TypeScript, only supported in Node.js (not in the browser).
// Construct the seed using a mnemonic, entropy or passkey
let mnemonic = "<mnemonic words>".to_string();
let seed = Seed::Mnemonic {
mnemonic,
passphrase: None,
};
// Create the default config
let mut config = default_config(Network::Mainnet);
config.api_key = Some("<breez api key>".to_string());
// Configure MySQL backend (MySQL 8.0+).
// Connection string format (URL only):
// "mysql://user:password@host:3306/dbname?ssl-mode=required"
let mut mysql_config = default_mysql_storage_config(
"mysql://user:password@localhost:3306/spark".to_string(),
);
// Optionally pool settings can be adjusted. Some examples:
mysql_config.max_pool_size = 8; // Max connections in pool
mysql_config.recycle_timeout_secs = Some(60); // Recycle idle connections after this many seconds
// Provide a custom CA certificate when using ssl-mode=verify_ca or verify_identity:
// mysql_config.root_ca_pem = Some("-----BEGIN CERTIFICATE-----\n...".to_string());
// Construct the connection pool. The same `Arc<MysqlConnectionPool>`
// can be passed to multiple SdkBuilders to share connections across SDKs;
// per-tenant scoping (rows isolated by seed identity) is preserved.
let pool = create_mysql_connection_pool(&mysql_config)?;
// Build the SDK with MySQL backend (storage, tree store, and token store)
let sdk = SdkBuilder::new(config, seed)
.with_mysql_connection_pool(pool)
.build()
.await?;
// Construct the seed using a mnemonic, entropy or passkey
let mnemonic = "<mnemonic words>"
let seed = Seed.mnemonic(mnemonic: mnemonic, passphrase: nil)
// Create the default config
var config = defaultConfig(network: Network.mainnet)
config.apiKey = "<breez api key>"
// Configure MySQL backend (MySQL 8.0+).
// Connection string format (URL only):
// "mysql://user:password@host:3306/dbname?ssl-mode=required"
var mysqlConfig = defaultMysqlStorageConfig(
connectionString: "mysql://user:password@localhost:3306/spark"
)
// Optionally pool settings can be adjusted. Some examples:
mysqlConfig.maxPoolSize = UInt32(8) // Max connections in pool
mysqlConfig.recycleTimeoutSecs = UInt64(60) // Recycle idle connections after this many seconds
// Provide a custom CA certificate when using ssl-mode=verify_ca or verify_identity:
// mysqlConfig.rootCaPem = "-----BEGIN CERTIFICATE-----\n..."
// Construct the connection pool. The same pool can be passed to
// multiple SdkBuilders to share connections across SDKs; per-tenant
// scoping (rows isolated by seed identity) is preserved.
let pool = try createMysqlConnectionPool(config: mysqlConfig)
// Build the SDK with MySQL backend (storage, tree store, and token store)
let builder = SdkBuilder(config: config, seed: seed)
await builder.withMysqlConnectionPool(pool: pool)
let sdk = try await builder.build()
// Construct the seed using a mnemonic, entropy or passkey
val mnemonic = "<mnemonic words>"
val seed = Seed.Mnemonic(mnemonic, null)
// Create the default config
val config = defaultConfig(Network.MAINNET)
config.apiKey = "<breez api key>"
// Configure MySQL backend (MySQL 8.0+).
// Connection string format (URL only):
// "mysql://user:password@host:3306/dbname?ssl-mode=required"
val mysqlConfig = defaultMysqlStorageConfig("mysql://user:password@localhost:3306/spark")
// Optionally pool settings can be adjusted. Some examples:
mysqlConfig.maxPoolSize = 8u // Max connections in pool
mysqlConfig.recycleTimeoutSecs = 60u // Recycle idle connections after this many seconds
// Construct the connection pool. The same pool can be passed to
// multiple SdkBuilders to share connections across SDKs; per-tenant
// scoping (rows isolated by seed identity) is preserved.
val pool = createMysqlConnectionPool(mysqlConfig)
try {
// Build the SDK with MySQL backend (storage, tree store, and token store)
val builder = SdkBuilder(config, seed)
builder.withMysqlConnectionPool(pool)
val sdk = builder.build()
} catch (e: Exception) {
// handle error
}
// Construct the seed using a mnemonic, entropy or passkey
var mnemonic = "<mnemonic words>";
var seed = new Seed.Mnemonic(mnemonic: mnemonic, passphrase: null);
// Create the default config
var config = BreezSdkSparkMethods.DefaultConfig(Network.Mainnet) with
{
apiKey = "<breez api key>"
};
// Configure MySQL backend (MySQL 8.0+).
// Connection string format (URL only):
// "mysql://user:password@host:3306/dbname?ssl-mode=required"
var mysqlConfig = BreezSdkSparkMethods.DefaultMysqlStorageConfig(
connectionString: "mysql://user:password@localhost:3306/spark"
);
// Optionally pool settings can be adjusted. Some examples:
mysqlConfig = mysqlConfig with
{
maxPoolSize = 8u, // Max connections in pool
recycleTimeoutSecs = 60ul // Recycle idle connections after this many seconds
};
// Construct the connection pool. The same pool can be passed to
// multiple SdkBuilders to share connections across SDKs; per-tenant
// scoping (rows isolated by seed identity) is preserved.
var pool = BreezSdkSparkMethods.CreateMysqlConnectionPool(config: mysqlConfig);
// Build the SDK with MySQL backend (storage, tree store, and token store)
var builder = new SdkBuilder(config: config, seed: seed);
await builder.WithMysqlConnectionPool(pool: pool);
var sdk = await builder.Build();
// Construct the seed using a mnemonic, entropy or passkey
const mnemonic = '<mnemonic words>'
const seed: Seed = { type: 'mnemonic', mnemonic, passphrase: undefined }
// Create the default config
const config = defaultConfig('mainnet')
config.apiKey = '<breez api key>'
// Configure MySQL backend (MySQL 8.0+).
// Connection string format (URL only):
// "mysql://user:password@host:3306/dbname?ssl-mode=required"
const mysqlConfig = defaultMysqlStorageConfig('mysql://user:password@localhost:3306/spark')
// Optionally pool settings can be adjusted. Some examples:
mysqlConfig.maxPoolSize = 8 // Max connections in pool
mysqlConfig.createTimeoutSecs = 30 // Timeout for establishing a new connection
mysqlConfig.recycleTimeoutSecs = 60 // Recycle idle connections after this many seconds
// Construct the connection pool. The same pool handle can be passed to
// multiple SdkBuilders to share connections across SDKs; per-tenant
// scoping (rows isolated by seed identity) is preserved.
const pool = createMysqlConnectionPool(mysqlConfig)
// Build the SDK with MySQL backend (storage, tree store, and token store)
let builder = SdkBuilder.new(config, seed)
builder = builder.withMysqlConnectionPool(pool)
const sdk = await builder.build()
async def init_sdk_mysql():
# Construct the seed using a mnemonic, entropy or passkey
mnemonic = "<mnemonic words>"
seed = Seed.MNEMONIC(mnemonic=mnemonic, passphrase=None)
# Create the default config
config = default_config(network=Network.MAINNET)
config.api_key = "<breez api key>"
# Configure MySQL backend (MySQL 8.0+).
# Connection string format (URL only):
# "mysql://user:password@host:3306/dbname?ssl-mode=required"
mysql_config = default_mysql_storage_config(
connection_string="mysql://user:password@localhost:3306/spark"
)
# Optionally pool settings can be adjusted. Some examples:
mysql_config.max_pool_size = 8 # Max connections in pool
mysql_config.recycle_timeout_secs = 60 # Recycle idle connections after this many seconds
# Provide a custom CA certificate when using ssl-mode=verify_ca or verify_identity:
# mysql_config.root_ca_pem = "-----BEGIN CERTIFICATE-----\n..."
# Construct the connection pool. The same pool can be passed to multiple
# SdkBuilders to share connections across SDKs; per-tenant scoping (rows
# isolated by seed identity) is preserved.
pool = create_mysql_connection_pool(config=mysql_config)
try:
# Build the SDK with MySQL backend (storage, tree store, and token store)
builder = SdkBuilder(config=config, seed=seed)
await builder.with_mysql_connection_pool(pool=pool)
sdk = await builder.build()
return sdk
except Exception as error:
logging.error(error)
raise
// Construct the seed using a mnemonic, entropy or passkey
mnemonic := "<mnemonic words>"
var seed breez_sdk_spark.Seed = breez_sdk_spark.SeedMnemonic{
Mnemonic: mnemonic,
Passphrase: nil,
}
// Create the default config
apiKey := "<breez api key>"
config := breez_sdk_spark.DefaultConfig(breez_sdk_spark.NetworkMainnet)
config.ApiKey = &apiKey
// Configure MySQL backend (MySQL 8.0+).
// Connection string format (URL only):
// "mysql://user:password@host:3306/dbname?ssl-mode=required"
mysqlConfig := breez_sdk_spark.DefaultMysqlStorageConfig("mysql://user:password@localhost:3306/spark")
// Optionally pool settings can be adjusted. Some examples:
mysqlConfig.MaxPoolSize = 8 // Max connections in pool
recycleTimeoutSecs := uint64(60)
mysqlConfig.RecycleTimeoutSecs = &recycleTimeoutSecs // Recycle idle connections after this many seconds
// Provide a custom CA certificate when using ssl-mode=verify_ca or verify_identity:
// rootCa := "-----BEGIN CERTIFICATE-----\n..."
// mysqlConfig.RootCaPem = &rootCa
// Construct the connection pool. The same pool can be passed to multiple
// SdkBuilders to share connections across SDKs; per-tenant scoping (rows
// isolated by seed identity) is preserved.
pool, err := breez_sdk_spark.CreateMysqlConnectionPool(mysqlConfig)
if err != nil {
return nil, err
}
// Build the SDK with MySQL backend (storage, tree store, and token store)
builder := breez_sdk_spark.NewSdkBuilder(config, seed)
builder.WithMysqlConnectionPool(pool)
sdk, err := builder.Build()
if err != nil {
return nil, err
}
Developer note
MySQL only accepts URL-form connection strings (mysql://user:password@host:3306/dbname); the key=value form supported by PostgreSQL is not available. TLS is enabled by appending ?ssl-mode=required (or verify_ca / verify_identity); when using verify_ca or verify_identity you can supply a custom root_ca_pem.
Sharing the same MySQL database with multiple SDK instances is incompatible with real-time sync. See Real-time sync server URL for how to disable it.
The MySQL tree store can use the same or a separate MySQL database as the MySQL storage. The tree store uses its own set of tables prefixed with tree_.
With Chain Service API docs
The SDK provides a default Bitcoin Chain Service implementation. If you want to use your own, you can provide it either by using With REST Chain Service or by implementing the Bitcoin Chain Service interface.
With REST Chain Service API docs
The SDK provides a default Bitcoin Chain Service implementation. If you want to use your own, you can provide it either by using With Chain Service or by providing a URL and optional credentials.
let url = "<your REST chain service URL>".to_string();
let chain_api_type = ChainApiType::MempoolSpace;
let optional_credentials = Credentials {
username: "<username>".to_string(),
password: "<password>".to_string(),
};
builder.with_rest_chain_service(url, chain_api_type, Some(optional_credentials))
let url = "<your REST chain service URL>"
let chainApiType = ChainApiType.mempoolSpace
let optionalCredentials = Credentials(
username: "<username>",
password: "<password>"
)
await builder.withRestChainService(
url: url,
apiType: chainApiType,
credentials: optionalCredentials
)
val url = "<your REST chain service URL>"
val chainApiType = ChainApiType.MEMPOOL_SPACE
val optionalCredentials = Credentials(
username = "<username>",
password = "<password>"
)
builder.withRestChainService(
url = url,
apiType = chainApiType,
credentials = optionalCredentials
)
var url = "<your REST chain service URL>";
var chainApiType = ChainApiType.MempoolSpace;
var optionalCredentials = new Credentials(
username: "<username>",
password: "<password>"
);
await builder.WithRestChainService(
url: url,
apiType: chainApiType,
credentials: optionalCredentials
);
const url = '<your REST chain service URL>'
const chainApiType = 'mempoolSpace'
const optionalCredentials: Credentials = {
username: '<username>',
password: '<password>'
}
builder = builder.withRestChainService(url, chainApiType, optionalCredentials)
const url = '<your REST chain service URL>'
const chainApiType = ChainApiType.MempoolSpace
const optionalCredentials: Credentials = {
username: '<username>',
password: '<password>'
}
await builder.withRestChainService(url, chainApiType, optionalCredentials)
String url = "<your REST chain service URL>";
var chainApiType = ChainApiType.mempoolSpace;
var optionalCredentials = Credentials(
username: "<username>",
password: "<password>",
);
builder.withRestChainService(
url: url,
apiType: chainApiType,
credentials: optionalCredentials,
);
url = "<your REST chain service URL>"
chain_api_type = ChainApiType.MEMPOOL_SPACE
optional_credentials = Credentials(
username="<username>",
password="<password>",
)
await builder.with_rest_chain_service(
url=url,
api_type=chain_api_type,
credentials=optional_credentials,
)
url := "<your REST chain service URL>"
chainApiType := breez_sdk_spark.ChainApiTypeMempoolSpace
optionalCredentials := &breez_sdk_spark.Credentials{
Username: "<username>",
Password: "<password>",
}
builder.WithRestChainService(url, chainApiType, optionalCredentials)
With Shared REST Chain Service API docs
With REST Chain Service builds a fresh chain service inside each SDK instance. Server processes hosting many wallets at once can share a single REST chain service between every SDK, so they reuse the same pooled HTTP client (and its HTTP/2 connection pool) instead of each opening a fresh one.
Construct one via new_rest_chain_servicenew_rest_chain_servicenewRestChainServicenewRestChainServicenewRestChainServicenewRestChainServicenewRestChainServiceNewRestChainServiceNewRestChainService and pass it to each SdkBuilderSdkBuilderSdkBuilderSdkBuilderSdkBuilderSdkBuilderSdkBuilderSdkBuilderSdkBuilder via with_chain_servicewith_chain_servicewithChainServicewithChainServicewithChainServicewithChainServicewithChainServiceWithChainServiceWithChainService. All SDK instances sharing the chain service must be configured for the same network.
With Fiat Service API docs
The SDK by default provides a list of available Fiat currencies and current exchange rates. If you want to use your own, you can provide it by implementing the Fiat Service interface.
With LNURL Client API docs
The LNURL Client is used to make REST requests specifically when interacting with LNURL. If you want to use your own, you can it provide by implementing the REST Service interface.
With Key Set API docs
The SDK uses by default the Default key set with the account number 1 on Mainnet (0 on Regtest). You can change this to alter the derivation path used with the provided seed:
- Default - Uses derivation path
m/8797555'/<account number>(use address index is ignored) - Taproot - Uses derivation path
m/86'/0'/<account number>'/0/0
(orm/86'/0'/0'/0/<account number>when use address index is enabled) - Native Segwit - Uses derivation path
m/84'/0'/<account number>'/0/0
(orm/84'/0'/0'/0/<account number>when use address index is enabled) - Wrapped Segwit - Uses derivation path
m/49'/0'/<account number>'/0/0
(orm/49'/0'/0'/0/<account number>when use address index is enabled) - Legacy - Uses derivation path
m/44'/0'/<account number>'/0/0
(orm/44'/0'/0'/0/<account number>when use address index is enabled)
let key_set_type = KeySetType::Default;
let use_address_index = false;
let optional_account_number = 21;
builder.with_key_set(KeySetConfig {
key_set_type,
use_address_index,
account_number: Some(optional_account_number),
})
let keySetType = KeySetType.default
let useAddressIndex = false
let optionalAccountNumber = UInt32(21)
let config = KeySetConfig(
keySetType: keySetType,
useAddressIndex: useAddressIndex,
accountNumber: optionalAccountNumber
)
await builder.withKeySet(config: config)
val keySetType = KeySetType.DEFAULT
val useAddressIndex = false
val optionalAccountNumber = 21u
val keySetConfig = KeySetConfig(
keySetType = keySetType,
useAddressIndex = useAddressIndex,
accountNumber = optionalAccountNumber
)
builder.withKeySet(keySetConfig)
var keySetType = KeySetType.Default;
var useAddressIndex = false;
var optionalAccountNumber = 21u;
var keySetConfig = new KeySetConfig(
keySetType: keySetType,
useAddressIndex: useAddressIndex,
accountNumber: optionalAccountNumber
);
await builder.WithKeySet(keySetConfig);
builder = builder.withKeySet({
keySetType: 'default',
useAddressIndex: false,
accountNumber: 21
})
const keySetConfig: KeySetConfig = {
keySetType: KeySetType.Default,
useAddressIndex: false,
accountNumber: 21
}
await builder.withKeySet(keySetConfig)
var keySetType = KeySetType.default_;
var useAddressIndex = false;
var optionalAccountNumber = 21;
builder.withKeySet(
config: KeySetConfig(
keySetType: keySetType,
useAddressIndex: useAddressIndex,
accountNumber: optionalAccountNumber,
),
);
key_set_type = KeySetType.DEFAULT
use_address_index = False
optional_account_number = 21
key_set_config = KeySetConfig(
key_set_type=key_set_type,
use_address_index=use_address_index,
account_number=optional_account_number,
)
await builder.with_key_set(config=key_set_config)
keySetType := breez_sdk_spark.KeySetTypeDefault
useAccountIndex := true
optionalAccountNumber := uint32(21)
keySetConfig := breez_sdk_spark.KeySetConfig{
KeySetType: keySetType,
UseAddressIndex: useAccountIndex,
AccountNumber: &optionalAccountNumber,
}
builder.WithKeySet(keySetConfig)
With Payment Observer API docs
By implementing the Payment Observer interface you can be notified before a payment is sent. It includes information about the provisional payment including the payment ID, amount to be sent (in satoshis or token base units) and payment details based on the payment method.
Note: Flutter currently does not support this.
pub(crate) struct ExamplePaymentObserver {}
#[async_trait]
impl PaymentObserver for ExamplePaymentObserver {
async fn before_send(
&self,
payments: Vec<ProvisionalPayment>,
) -> Result<(), PaymentObserverError> {
for payment in payments {
info!(
"About to send payment: {:?} of amount {:?}",
payment.payment_id, payment.amount
);
}
Ok(())
}
}
pub(crate) fn with_payment_observer(builder: SdkBuilder) -> SdkBuilder {
let observer = ExamplePaymentObserver {};
builder.with_payment_observer(Arc::new(observer))
}
class ExamplePaymentObserver: PaymentObserver {
func beforeSend(payments: [ProvisionalPayment]) async {
for payment in payments {
print("About to send payment: \(payment.paymentId) of amount \(payment.amount)")
}
}
}
func withPaymentObserver(builder: SdkBuilder) async {
let paymentObserver = ExamplePaymentObserver()
await builder.withPaymentObserver(paymentObserver: paymentObserver)
}
class ExamplePaymentObserver : PaymentObserver {
override suspend fun beforeSend(payments: List<ProvisionalPayment>) {
for (payment in payments) {
// Log.v("PaymentObserver", "About to send payment: ${payment.paymentId} of amount ${payment.amount}")
}
}
}
suspend fun withPaymentObserver(builder: SdkBuilder) {
val paymentObserver = ExamplePaymentObserver()
builder.withPaymentObserver(paymentObserver)
}
class ExamplePaymentObserver : PaymentObserver
{
public async Task BeforeSend(ProvisionalPayment[] payments)
{
foreach (var payment in payments)
{
Console.WriteLine($"About to send payment {payment.paymentId} of amount {payment.amount}");
}
}
}
async Task WithPaymentObserver(SdkBuilder builder)
{
var paymentObserver = new ExamplePaymentObserver();
await builder.WithPaymentObserver(paymentObserver);
}
class ExamplePaymentObserver {
beforeSend = async (payments: ProvisionalPayment[]) => {
for (const payment of payments) {
console.log(`About to send payment: ${payment.paymentId} of amount ${payment.amount}`)
}
}
}
const exampleWithPaymentObserver = (builder: SdkBuilder): SdkBuilder => {
const paymentObserver = new ExamplePaymentObserver()
return builder.withPaymentObserver(paymentObserver)
}
class ExamplePaymentObserver {
beforeSend = async (payments: ProvisionalPayment[]) => {
for (const payment of payments) {
console.log(`About to send payment: ${payment.paymentId} of amount ${payment.amount}`)
}
}
}
const exampleWithPaymentObserver = async (builder: SdkBuilder) => {
const paymentObserver = new ExamplePaymentObserver()
await builder.withPaymentObserver(paymentObserver)
}
class ExamplePaymentObserver(PaymentObserver):
async def before_send(self, payments: typing.List[ProvisionalPayment]):
for payment in payments:
logging.debug(f"About to send payment {payment.payment_id} of amount {payment.amount}")
async def with_payment_observer(builder: SdkBuilder):
payment_observer = ExamplePaymentObserver()
await builder.with_payment_observer(payment_observer=payment_observer)
type ExamplePaymentObserver struct{}
func (ExamplePaymentObserver) BeforeSend(payments []breez_sdk_spark.ProvisionalPayment) error {
for _, payment := range payments {
log.Printf("About to send payment: %v of amount %v", payment.PaymentId, payment.Amount)
}
return nil
}
func WithPaymentObserver(builder *breez_sdk_spark.SdkBuilder) {
observer := ExamplePaymentObserver{}
builder.WithPaymentObserver(observer)
}
With SSP Connection Manager API docs
An SSP Connection Manager owns the HTTP client used for SSP GraphQL traffic. By default each SDK instance builds its own. Server processes hosting many wallets at once can share a single SSP Connection Manager between every SDK, so they reuse the same pooled HTTP client (and its HTTP/2 connection pool) instead of each opening a fresh one.
Construct one via new_ssp_connection_managernew_ssp_connection_managernewSspConnectionManagernewSspConnectionManagernewSspConnectionManagernewSspConnectionManagernewSspConnectionManagerNewSspConnectionManagerNewSspConnectionManager and pass it to each SdkBuilderSdkBuilderSdkBuilderSdkBuilderSdkBuilderSdkBuilderSdkBuilderSdkBuilderSdkBuilder via with_ssp_connection_managerwith_ssp_connection_managerwithSspConnectionManagerwithSspConnectionManagerwithSspConnectionManagerwithSspConnectionManagerwithSspConnectionManagerWithSspConnectionManagerWithSspConnectionManager. Connections close when the last reference to the SSP Connection Manager is dropped; calling disconnectdisconnectdisconnectdisconnectdisconnectdisconnectdisconnectDisconnectDisconnect on an SDK instance does not affect them.
Developer note
The user agent of the first SDK to construct the SSP Connection Manager is reused for all subsequent instances.
With Connection Manager API docs
A Connection Manager owns the gRPC channels to the Spark operators. By default each SDK instance builds its own. Server processes hosting many wallets at once can share a single Connection Manager between every SDK, so they reuse the same channels instead of each opening a fresh set.
Construct one via new_connection_managernew_connection_managernewConnectionManagernewConnectionManagernewConnectionManagernewConnectionManagernewConnectionManagerNewConnectionManagerNewConnectionManager and pass it to each SdkBuilderSdkBuilderSdkBuilderSdkBuilderSdkBuilderSdkBuilderSdkBuilderSdkBuilderSdkBuilder via with_connection_managerwith_connection_managerwithConnectionManagerwithConnectionManagerwithConnectionManagerwithConnectionManagerwithConnectionManagerWithConnectionManagerWithConnectionManager. Connections close when the last reference to the Connection Manager is dropped; calling disconnectdisconnectdisconnectdisconnectdisconnectdisconnectdisconnectDisconnectDisconnect on an SDK instance does not affect them.
The connections_per_operator argument controls how many connections the manager opens to each operator:
None— one connection per operator, multiplexed across every SDK sharing this manager. The right choice for almost every deployment.Some(n)— opensnconnections per operator and balances requests across them. Worth setting only if the single shared connection has become a bottleneck — for example, latency that climbs with throughput, or operators deployed behind an L7 load balancer where you want client-side fan-out across backend instances.
Developer note
All SDK instances sharing a Connection Manager must be configured for the same network and operator pool. The cache is keyed by operator address, so the TLS settings and user agent of the first SDK to connect to a given operator are reused for everyone afterwards.
Browser
The Connection Manager is not exposed in the browser. Browsers maintain a single HTTP/2 connection per origin and multiplex everything over it; the SDK cannot create or share more.
Node.js
Node's global fetch (undici) negotiates HTTP/2 with the Spark operators automatically and opens additional connections per origin as needed, so most deployments need no tuning. If you do want to cap or expand the per-origin pool, configure undici globally before initialising the SDK:
import { Agent, setGlobalDispatcher } from 'undici'
setGlobalDispatcher(new Agent({ connections: 8 }))
This affects every fetch in the process, including the SDK's gRPC-web traffic.