Lexe Python SDK¶
Welcome to the API reference docs for the Lexe Python SDK.
Lexe is a self-custodial Lightning wallet with always-online nodes. Using the Lexe Python SDK, your app can control a Lexe wallet programmatically; send and receive payments, view payment history, and even provision new wallets.
To get started, see docs.lexe.tech/python/quickstart.
View the source at lexe-public/sdk-uniffi.
You can find releases at lexe-app/lexe-sdk releases.
Configuration¶
- class lexe.WalletConfig(*args, **kwargs)¶
Configuration for a wallet environment.
Use the factory constructors to create configs for standard environments.
Example:
# Production (mainnet) config = WalletConfig.mainnet() # Staging (testnet) config = WalletConfig.testnet3() # Local development (regtest) config = WalletConfig.regtest() config = WalletConfig.regtest(use_sgx=True, gateway_url="http://localhost:8080")
- classmethod mainnet()¶
Create a config for mainnet (production).
- Returns:
A WalletConfig for the mainnet environment.
- Return type:
- classmethod regtest(use_sgx=False, gateway_url=<object object>)¶
Create a config for regtest (local development).
- Parameters:
use_sgx (bool) – Whether SGX is enabled. Defaults to
False.gateway_url (object | str | None) – Gateway URL override, or
Nonefor default.
- Returns:
A WalletConfig for the regtest environment.
- Return type:
- classmethod testnet3()¶
Create a config for testnet3 (staging).
- Returns:
A WalletConfig for the testnet3 environment.
- Return type:
- property deploy_env: DeployEnv¶
Get the configured deployment environment.
- Returns:
The
DeployEnvfor this config.
- property gateway_url: str | None¶
Get the gateway URL for this environment.
- Returns:
The gateway URL string, or
Noneif using the default.
- property network: Network¶
Get the configured Bitcoin network.
- Returns:
The
Networkfor this config.
- seedphrase_path(lexe_data_dir=<object object>)¶
Returns the path to the seedphrase file for this environment.
Mainnet:
<lexe_data_dir>/seedphrase.txtOther environments:
<lexe_data_dir>/seedphrase.<env>.txt
- Parameters:
lexe_data_dir (object | str | None) – Base data directory path. Defaults to
~/.lexe.- Returns:
The absolute path to the seedphrase file.
- Return type:
str
Example:
config = WalletConfig.mainnet() path = config.seedphrase_path() # '/home/user/.lexe/seedphrase.txt'
- property use_sgx: bool¶
Whether SGX is enabled for this config.
- Returns:
Trueif SGX is enabled,Falseotherwise.
- class lexe.DeployEnv(*values)¶
Deployment environment for a wallet.
DEV – Development environment (local regtest).
STAGING – Staging environment (testnet).
PROD – Production environment (mainnet).
- DEV = 0¶
Development environment.
- STAGING = 1¶
Staging environment.
- PROD = 2¶
Production environment.
- class lexe.Network(*values)¶
Bitcoin network to use.
MAINNET – Bitcoin mainnet.
TESTNET3 – Bitcoin testnet3.
TESTNET4 – Bitcoin testnet4.
SIGNET – Bitcoin signet.
REGTEST – Bitcoin regtest (local development).
- MAINNET = 0¶
Bitcoin mainnet.
- TESTNET3 = 1¶
Bitcoin testnet3.
- TESTNET4 = 2¶
Bitcoin testnet4.
- SIGNET = 3¶
Bitcoin signet.
- REGTEST = 4¶
Bitcoin regtest.
Credentials¶
- class lexe.RootSeed(*args, **kwargs)¶
The secret root seed for deriving all user keys and credentials.
Create with
RootSeed.generate(), from raw bytes withRootSeed.from_bytes(), or load from a file withRootSeed.read()orRootSeed.read_from_path().Example:
# Generate a new random seed seed = RootSeed.generate() # Or create from raw bytes import os seed = RootSeed.from_bytes(os.urandom(32)) # Or load from the default seedphrase path for this environment config = WalletConfig.mainnet() seed = RootSeed.read(config) # Or load from a specific file path seed = RootSeed.read_from_path("/home/user/.lexe/seedphrase.txt")
- classmethod from_bytes(seed_bytes)¶
Construct a root seed from raw bytes. The seed must be exactly 32 bytes.
- Parameters:
seed_bytes (bytes) – Raw 32-byte seed.
- Returns:
A RootSeed from the given bytes.
- Raises:
FfiError – If the input is not exactly 32 bytes.
- Return type:
Example:
import os seed = RootSeed.from_bytes(os.urandom(32))
- classmethod from_hex(hex_string)¶
Construct a root seed from a 64-character hex string.
- Parameters:
hex_string (str) – 64-character hex-encoded seed.
- Returns:
A RootSeed from the given hex string.
- Raises:
FfiError – If the hex string is invalid or the wrong length.
- Return type:
Example:
seed = RootSeed.from_hex("a1b2c3...")
- classmethod from_mnemonic(mnemonic)¶
Construct a root seed from a BIP39 mnemonic string.
- Parameters:
mnemonic (str) – Space-separated BIP39 mnemonic words.
- Returns:
The root seed derived from the mnemonic.
- Raises:
FfiError – If the mnemonic is invalid.
- Return type:
Example:
seed = RootSeed.from_mnemonic("abandon abandon ... about")
- classmethod generate()¶
Generate a new random root seed.
- Returns:
A new randomly-generated RootSeed.
- Return type:
Example:
seed = RootSeed.generate()
- classmethod password_decrypt(password, encrypted)¶
Decrypt a password-encrypted root seed.
- Parameters:
password (str) – The password used to encrypt.
encrypted (bytes) – The encrypted seed bytes.
- Returns:
The decrypted RootSeed.
- Raises:
FfiError – If decryption fails (wrong password or corrupted data).
- Return type:
Example:
encrypted = seed.password_encrypt("my-password") decrypted = RootSeed.password_decrypt("my-password", encrypted)
- classmethod read(env_config)¶
Reads a root seed from
~/.lexe/seedphrase[.env].txt.- Parameters:
env_config (WalletConfig) – The wallet environment config.
- Returns:
The root seed loaded from the file.
- Raises:
SeedFileError.NotFound – If the seedphrase file doesn’t exist.
SeedFileError.ParseError – If the file exists but cannot be parsed.
- Return type:
Example:
config = WalletConfig.mainnet() try: seed = RootSeed.read(config) except SeedFileError.NotFound: seed = RootSeed.from_bytes(os.urandom(32))
- classmethod read_from_path(path)¶
Reads a root seed from a seedphrase file containing a BIP39 mnemonic.
- Parameters:
path (str) – Absolute path to the seedphrase file.
- Returns:
The root seed loaded from the file.
- Raises:
SeedFileError.NotFound – If the file doesn’t exist.
SeedFileError.ParseError – If the file cannot be parsed.
- Return type:
Example:
try: seed = RootSeed.read_from_path("/home/user/.lexe/seedphrase.txt") except SeedFileError.NotFound: seed = RootSeed.from_bytes(os.urandom(32))
- derive_node_pk()¶
Derive the node public key.
- Returns:
The hex-encoded secp256k1 node public key string.
- Return type:
str
Example:
seed = RootSeed.generate() print(f"Node PK: {seed.derive_node_pk()}")
- derive_user_pk()¶
Derive the user’s public key.
- Returns:
The hex-encoded ed25519 user public key string.
- Return type:
str
Example:
seed = RootSeed.generate() print(f"User PK: {seed.derive_user_pk()}")
- password_encrypt(password)¶
Encrypt this root seed under the given password.
- Parameters:
password (str) – The password to encrypt with.
- Returns:
The encrypted seed as bytes.
- Raises:
FfiError – If encryption fails.
- Return type:
bytes
Example:
encrypted = seed.password_encrypt("my-password")
- to_bytes()¶
Return the 32-byte root seed.
- Returns:
The raw seed bytes.
- Return type:
bytes
- to_hex()¶
Encode the root secret as a 64-character hex string.
- Returns:
The hex-encoded seed string.
- Return type:
str
- to_mnemonic()¶
Return this root seed’s mnemonic as a space-separated string.
- Returns:
The BIP39 mnemonic string.
- Return type:
str
Example:
seed = RootSeed.generate() print(seed.to_mnemonic())
- write(env_config)¶
Writes this root seed’s mnemonic to
~/.lexe/seedphrase[.env].txt.Creates parent directories if needed.
- Parameters:
env_config (WalletConfig) – The wallet environment config.
- Raises:
SeedFileError.AlreadyExists – If the file already exists.
SeedFileError.IoError – If the file cannot be written.
- Return type:
None
Example:
config = WalletConfig.mainnet() seed.write(config)
- write_to_path(path)¶
Writes this root seed’s mnemonic to the given file path.
Creates parent directories if needed.
- Parameters:
path (str) – Absolute path to write the seedphrase file.
- Raises:
SeedFileError.AlreadyExists – If the file already exists.
SeedFileError.IoError – If the file cannot be written.
- Return type:
None
Example:
seed = RootSeed.from_bytes(os.urandom(32)) seed.write_to_path("/home/user/.lexe/seedphrase.txt")
- class lexe.ClientCredentials(*args, **kwargs)¶
Scoped and revocable credentials for controlling a Lexe user node.
These are useful when you want node access without exposing the user’s
RootSeed, which is irrevocable. Wrap intoCredentialsto use with wallet constructors.- from_string(s)¶
Parse credentials from a portable string.
- Parameters:
s (str)
- Return type:
- export_string()¶
Export credentials as a portable string (round-trips with
from_string).- Return type:
str
- classmethod from_string(s)¶
Parse client credentials from a string.
- Parameters:
s (str)
- Return type:
- export_string()¶
Export these credentials as a portable string.
The returned string can be passed to [ClientCredentials::from_string] to reconstruct the credentials.
- Return type:
str
Wallet¶
- class lexe.LexeWallet(*args, **kwargs)¶
Synchronous wallet handle for interacting with a Lexe Lightning node.
For async usage, use
AsyncLexeWallet.Create a wallet using one of the constructors:
load()– Load from existing local state.fresh()– Create fresh local state (deletes existing).load_or_fresh()– Load or create if none exists.
Then call
signup()andprovision()before using payment methods.Example:
config = WalletConfig.mainnet() seed = RootSeed.read(config) # Raises SeedFileError.NotFound if missing creds = Credentials.from_root_seed(seed) wallet = LexeWallet.load_or_fresh(config, creds) wallet.signup(seed) wallet.provision(creds) info = wallet.node_info() print(f"Balance: {info.balance_sats} sats")
- analyze(payable)¶
Analyze a Bitcoin or Lightning payment string.
Returns the routes found (as
AnalyzeResponse).payablesholds outbound payment routes, sorted from most to least recommended; eachPayableDetailsincludes the payable string, parsedPaymentMethod, amount constraints, description, and expiration.claimablesholds inbound claim routes (e.g. LNURL-withdraw); eachClaimableDetailsincludes the claimable string, parsedClaimMethod, description, and amount constraints.Supported encodings:
BIP 321 URI:
bitcoin:bc1...Lightning URI:
lightning:ln...BOLT 11 invoice:
lnbc1...BOLT 12 offer:
lno1...Onchain bitcoin address:
bc1...Human Bitcoin Address:
₿username@lexe.appLightning Address:
username@lexe.appLNURL:
lnurl1...orlnurlp://domain.com/path
Within the encodings, the following payment methods are supported:
BOLT 11 invoice
BOLT 12 offer
Bitcoin address
Lightning Address
LNURL-pay
And the following claim methods are supported:
LNURL-withdraw
- Parameters:
payable (str) – The string-encoded payment method.
- Returns:
An
AnalyzeResponsewithpayables(outbound payment routes, sorted from most to least recommended) andclaimables(inbound claim routes, e.g. LNURL-withdraw).- Raises:
FfiError – If no valid payment methods were found.
- Return type:
AnalyzeResponse
Example:
resp = wallet.analyze("username@lexe.app") details = resp.payables[0] print(details.payable) # "https://lexe.app/.well-known/lnurlp/satoshi" print(details.method) # PaymentMethod.LNURL_PAY(...) print(details.min_amount_sats) # minimum payable amount print(details.max_amount_sats) # maximum payable amount
- buy_with_cash_app(amount_sats)¶
Buy Bitcoin with Cash App.
Given an amount of Bitcoin that the user wants to buy, returns a Cash App URL that you can redirect your user to complete the purchase. Cash App buys are instant and land directly into Lexe wallet.
- Parameters:
amount_sats (int) – Amount of Bitcoin to buy in satoshis. Must be at least 5000.
- Returns:
A
CashAppBuyResponsewhoseredirect_urlyou should send your user to, to complete the purchase. For the smoothest experience, encourage them to open it on a device where Cash App is already set up.- Raises:
FfiError – If the amount is below the minimum or the request fails.
- Return type:
CashAppBuyResponse
Example:
resp = wallet.buy_with_cash_app(5000) print(resp.redirect_url) # Redirect your user here
- clear_payments()¶
Clear all locally cached payment data for this wallet.
Clears the local payment cache only. Remote data on the node is not affected. Call
sync_payments()to re-populate.- Raises:
FfiError – If the local database cannot be cleared.
- Return type:
None
- close_channel(channel_id)¶
Close a Lightning channel.
- Parameters:
channel_id (str) – The id of the channel to close, serialized as a 64-character hex string (32 bytes).
- Raises:
FfiError – If the channel could not be closed.
- Return type:
None
Example:
wallet.close_channel(channel_id)
- create_client(expires_at_ms, label=<object object>)¶
Create a new client authorized to control this node.
The returned credentials grant control of this node without exposing the root seed, and can be revoked at any time with
revoke_client().Warning
Anyone with the returned credentials can control this node’s funds. Store them somewhere safe.
- Parameters:
expires_at_ms (int | None) – The client’s expiration (ms since UNIX epoch), or
Nonefor a client that never expires. Use carefully!label (object | str | None) – An optional label of at most 64 UTF-8 bytes.
- Returns:
A
CreateClientResponsewith the new client’s public key and credentials.- Raises:
FfiError – If the request fails.
- Return type:
CreateClientResponse
Example:
# Pass expires_at_ms=None to opt into a never-expiring client. resp = wallet.create_client(expires_at_ms=None, label="my-server") # Store the credentials somewhere safe; reload later with # ClientCredentials.from_string(...). creds_str = resp.client_credentials.export_string()
- create_invoice(expiration_secs=<object object>, amount_sats=<object object>, description=<object object>, personal_note=<object object>, partner_pk=<object object>, partner_prop_fee_ppm=<object object>, partner_base_fee_sats=<object object>)¶
Create a BOLT 11 Lightning invoice.
- Parameters:
expiration_secs (object | int | None) – Invoice expiry in seconds (e.g.
3600for 1 hour), orNonefor a default of86400(1 day).amount_sats (object | int | None) – Amount in satoshis, or
Nonefor an amountless invoice.description (object | str | None) – Optional description shown to the payer.
personal_note (object | str | None) – Optional personal note (not visible to the payer). If provided, it must be non-empty and <= 200 chars / 512 UTF-8 bytes.
partner_pk (object | str | None) – Hex-encoded user_pk of a Lexe partner setting custom fees. Must be set for partner fee fields to take effect.
partner_prop_fee_ppm (object | int | None) – Partner proportional fee in parts per million (ppm). Must be set if
partner_pkis set. Min: 5000, Max: 500000 (50%).partner_base_fee_sats (object | int | None) – Partner base fee in satoshis. If set,
amount_satsmust also be set.
- Returns:
A
CreateInvoiceResponsewith the invoice string and metadata.- Raises:
FfiError – If the node is offline or the request fails.
- Return type:
Example:
resp = wallet.create_invoice(3600, 1000, "Coffee") print(resp.invoice) # BOLT 11 invoice string print(resp.amount_sats) # 1000
- create_offer(description=<object object>, min_amount_sats=<object object>, expiration_secs=<object object>)¶
Create a BOLT 12 offer to receive Lightning payments.
Unlike invoices, offers are reusable: multiple payments can be made to it, including from multiple payers.
- Parameters:
description (object | str | None) – Optional description shown to the sender when they scan the offer. If provided, it must be non-empty and no longer than 200 chars / 512 UTF-8 bytes.
min_amount_sats (object | int | None) – Optional minimum payment amount in satoshis.
expiration_secs (object | int | None) – Optional expiration time in seconds from now.
- Returns:
A
CreateOfferResponsewith the BOLT 12 offer string.- Raises:
FfiError – If the node is offline or the request fails.
- Return type:
CreateOfferResponse
Example:
resp = wallet.create_offer(description="Donations") print(resp.offer) # BOLT 12 offer string
- classmethod fresh(env_config, credentials, lexe_data_dir=<object object>)¶
Create a fresh wallet, deleting any existing local state for this user.
Data for other users and environments is not affected.
- Parameters:
env_config (WalletConfig) – Wallet environment configuration.
credentials (Credentials) – Authentication credentials (see
Credentials).lexe_data_dir (object | str | None) – Base data directory (default:
~/.lexe).
- Returns:
A new LexeWallet instance.
- Raises:
FfiError – If wallet creation fails.
- Return type:
- get_human_bitcoin_address()¶
Get the user’s Human Bitcoin Address.
The Human Bitcoin Address (BIP 353), e.g.
₿username@lexe.app, is a human-readable address which others can pay to send Bitcoin to this wallet. It also works as a Lightning Address (username@lexe.app) for senders which support LNURL but not BIP 353.- Returns:
A
GetHumanBitcoinAddressResponsewith the Human Bitcoin Address, the Lightning Address, the BOLT 12 offer that the address resolves to, and whether the username can currently be changed.- Raises:
FfiError – If the request fails.
- Return type:
GetHumanBitcoinAddressResponse
Example:
resp = wallet.get_human_bitcoin_address() print(resp.human_bitcoin_address)
- get_payment(index)¶
Get a specific payment by its index.
- get_updated_payments(start_index=<object object>, limit=<object object>)¶
Get a batch of payments in ascending
updated_atorder, starting from a givenupdated_atindex.Useful for tailing / syncing payment updates as they occur. Fetches directly from the user node (does not read from or write to the local payments cache).
- Parameters:
start_index (object | str | None) – The cursor at which the results should start, exclusive. If
None, the least recently updated payments will be returned first.limit (object | int | None) – Maximum number of payments to return. Max 100, defaults to 50.
- Returns:
A
GetUpdatedPaymentsResponsewith the updated payments and anupdated_indexcursor for fetching the next page.- Raises:
FfiError – If
start_indexis malformed or the request fails.- Return type:
GetUpdatedPaymentsResponse
Example:
resp = wallet.get_updated_payments() for p in resp.payments: print(f"{p.index}: {p.status}") # Next page if resp.updated_index is not None: resp = wallet.get_updated_payments(start_index=resp.updated_index)
- list_channels()¶
List this node’s Lightning channels.
All of this node’s Lightning channels are connected to the Lexe LSP.
- Returns:
A list of
ChannelDetails.- Raises:
FfiError – If the node is unreachable.
- Return type:
List[ChannelDetails]
Example:
for channel in wallet.list_channels(): print(f"{channel.channel_id}: {channel.our_balance_sats} sats")
- list_clients()¶
List the clients authorized to control this node.
Revoked and expired clients are not included.
- Returns:
A dict mapping each client’s hex-encoded public key to its
ClientInfo.- Raises:
FfiError – If the request fails.
- Return type:
dict[str, ClientInfo]
Example:
for pk, client in wallet.list_clients().items(): print(f"{pk}: {client.label}")
- list_payments(filter, order=<object object>, limit=<object object>, after=<object object>)¶
List payments from local storage with cursor-based pagination.
Reads from the local database only (no network calls). Use
sync_payments()to fetch the latest data from the node if needed.- Parameters:
filter (PaymentFilter) – Which payments to include:
PaymentFilter.ALL,PaymentFilter.PENDING,PaymentFilter.COMPLETED,PaymentFilter.FAILED, orPaymentFilter.FINALIZED(completed or failed).order (object | Order | None) – Sort order (
Order.DESCorOrder.ASC). Defaults toDESC(newest first).limit (object | int | None) – Maximum number of payments to return. Defaults to
100.after (object | str | None) – Pagination cursor. Pass
next_indexfrom a previous response to get the next page. Defaults toNone(first page).
- Returns:
A
ListPaymentsResponsewith payments and anext_indexcursor for fetching the next page (Noneif no more results).- Raises:
FfiError – If
afteris not a valid payment index string.- Return type:
Example:
wallet.sync_payments() # First page resp = wallet.list_payments(PaymentFilter.ALL) for p in resp.payments: print(f"{p.index}: {p.amount_sats} sats ({p.status})") # Next page if resp.next_index is not None: resp = wallet.list_payments(PaymentFilter.ALL, after=resp.next_index)
- classmethod load(env_config, credentials, lexe_data_dir=<object object>)¶
Load an existing wallet from local state.
Raises
LoadWalletError.NotFoundif no local data exists. UseLexeWallet.fresh()to create local state.- Parameters:
env_config (WalletConfig) – Wallet environment configuration.
credentials (Credentials) – Authentication credentials (see
Credentials).lexe_data_dir (object | str | None) – Base data directory (default:
~/.lexe).
- Returns:
The loaded LexeWallet instance.
- Raises:
LoadWalletError.NotFound – If no local data exists.
LoadWalletError.LoadFailed – If local data is corrupted.
- Return type:
Example:
try: wallet = LexeWallet.load(config, creds) except LoadWalletError.NotFound: wallet = LexeWallet.fresh(config, creds)
- classmethod load_or_fresh(env_config, credentials, lexe_data_dir=<object object>)¶
Load an existing wallet, or create a fresh one if none exists. If you are authenticating with client credentials, this is generally what you want to use.
- Parameters:
env_config (WalletConfig) – Wallet environment configuration.
credentials (Credentials) – Authentication credentials (see
Credentials).lexe_data_dir (object | str | None) – Base data directory (default:
~/.lexe).
- Returns:
A LexeWallet instance (loaded or newly created).
- Raises:
FfiError – If wallet creation fails.
- Return type:
- node_info()¶
Get information about the node (balance, channels, version).
- Returns:
A
NodeInfowith the node’s current state.- Raises:
FfiError – If the node is unreachable.
- Return type:
Example:
info = wallet.node_info() print(f"Balance: {info.balance_sats} sats") print(f"Channels: {info.num_usable_channels}/{info.num_channels}")
- open_channel(value_sats, user_channel_id=<object object>)¶
Open a Lightning channel from this node to Lexe’s LSP.
- Parameters:
value_sats (int) – The value of the channel to open, in satoshis.
user_channel_id (object | str | None) – An optional idempotency key, serialized as a 32-character hex string (16 bytes). Retrying with the same id won’t open a duplicate channel. A random id is generated if omitted.
- Returns:
An
OpenChannelResponsewith the ids of the newly opened channel.- Raises:
FfiError – If the channel could not be opened.
- Return type:
OpenChannelResponse
Example:
resp = wallet.open_channel(value_sats=100_000) print(f"Opened channel: {resp.channel_id}")
- pay(payable, amount_sats=<object object>, message=<object object>, personal_note=<object object>)¶
Pay any string which encodes a Bitcoin or Lightning payment method.
If there are multiple encoded payment methods, the best recommended one is chosen. For finer control, use
analyze()first, then call the specific pay method (pay_invoice(),pay_offer(), etc.).Supported encodings:
BIP 321 URI:
bitcoin:bc1...Lightning URI:
lightning:ln...BOLT 11 invoice:
lnbc1...BOLT 12 offer:
lno1...Onchain bitcoin address:
bc1...Human Bitcoin Address:
₿username@lexe.appLightning Address:
username@lexe.appLNURL:
lnurl1...orlnurlp://domain.com/path
- Parameters:
payable (str) – The string to pay.
amount_sats (object | int | None) – Amount in satoshis to pay. Required if the payable has no encoded amount. If both the payable and
amount_satsspecify an amount, they must match. For LNURL payables, the amount must fall within the receiver’s minimum and maximum range.message (object | str | None) – Optional message to the recipient (BOLT12 offers, LNURL).
personal_note (object | str | None) – Optional personal note (not visible to recipient).
- Returns:
The resulting
Payment, returned once it reaches a terminal state (completed or failed). Exception: onchain sends return immediately with the payment still in a pending state, since on-chain confirmation takes ~1 hour.- Raises:
FfiError – If the payable string is invalid, the amount is missing or out of range, or payment initiation fails.
- Return type:
Example:
payment = wallet.pay("username@lexe.app", amount_sats=1000) print(f"Payment {payment.status}")
- pay_invoice(invoice, fallback_amount_sats=<object object>, personal_note=<object object>)¶
Pay a BOLT 11 Lightning invoice.
- Parameters:
invoice (str) – BOLT 11 invoice string to pay.
fallback_amount_sats (object | int | None) – Required if the invoice has no amount encoded.
personal_note (object | str | None) – Optional personal note (not visible to the receiver). If provided, it must be non-empty and <= 200 chars / 512 UTF-8 bytes.
- Returns:
The resulting
Payment, returned once it reaches a terminal state (completed or failed).- Raises:
FfiError – If the invoice is invalid or payment initiation fails.
- Return type:
Example:
payment = wallet.pay_invoice(bolt11_string) print(f"Payment {payment.status}")
- pay_lnurl(lnurl, amount_sats, message=<object object>, personal_note=<object object>)¶
Pay an LNURL via the
payRequestflow.Use
analyze()to get the associatedLnurlPayRequest, which contains information on amount constraints, message length limits, and more.- Parameters:
lnurl (str) – LNURL string to pay to.
amount_sats (int) – Amount to pay in satoshis. If the LNURL endpoint specifies a minimum or maximum amount, this value must satisfy those limits.
message (object | str | None) – Optional message visible to the recipient. It is only sent if the LNURL endpoint supports it, and is truncated to the endpoint’s length limit if needed.
personal_note (object | str | None) – Optional personal note (not visible to the receiver). If provided, it must be non-empty and no longer than 200 chars / 512 UTF-8 bytes.
- Returns:
The resulting
Payment, returned once it reaches a terminal state (completed or failed).- Raises:
FfiError – If the LNURL is invalid or payment initiation fails.
- Return type:
Example:
payment = wallet.pay_lnurl(lnurl_string, 1000) print(f"Payment {payment.status}")
- pay_offer(offer, amount_sats, message=<object object>, personal_note=<object object>)¶
Pay a BOLT 12 offer over Lightning.
- Parameters:
offer (str) – BOLT 12 offer string to pay.
amount_sats (int) – Amount to pay in satoshis.
message (object | str | None) – Optional message visible to the receiver. If provided, it must be non-empty and no longer than 200 chars / 512 UTF-8 bytes.
personal_note (object | str | None) – Optional personal note (not visible to the receiver). If provided, it must be non-empty and no longer than 200 chars / 512 UTF-8 bytes.
- Returns:
The resulting
Payment, returned once it reaches a terminal state (completed or failed).- Raises:
FfiError – If the offer is invalid or payment initiation fails.
- Return type:
Example:
payment = wallet.pay_offer(bolt12_offer, 1000) print(f"Payment {payment.status}")
- provision(credentials)¶
Ensures the wallet is provisioned to all recent trusted releases.
Call every time the wallet is loaded to keep the node running the most up-to-date enclave software.
- Parameters:
credentials (Credentials) – Authentication credentials (see
Credentials).- Raises:
FfiError – If provisioning fails.
- Return type:
None
Example:
wallet = LexeWallet.load_or_fresh(config, creds) wallet.provision(creds)
- revoke_client(client_pk)¶
Permanently revoke a client, making its credentials invalid for authentication. This cannot be undone.
- Parameters:
client_pk (str) – Hex-encoded public key of the client to revoke.
- Returns:
The revoked
ClientInfo.- Raises:
FfiError – If
client_pkis malformed or the request fails.- Return type:
ClientInfo
- signup(root_seed, partner_pk=<object object>)¶
Register this user with Lexe and provision their node.
Call after creating the wallet for the first time. Idempotent: calling again for an already-signed-up user is safe.
Important
After signup, persist the user’s root seed! Without it, users lose access to their funds permanently.
- Parameters:
root_seed (RootSeed) – The user’s root seed.
partner_pk (object | str | None) – Optional hex-encoded user public key of your company account. Set to earn a share of fees.
- Raises:
FfiError – If signup or provisioning fails.
- Return type:
None
Example:
wallet.signup(seed) seed.write(config) # Persist seed after signup!
- sync_payments()¶
Sync payments from the user node to the local payments cache.
Call periodically to keep local payment data up to date.
- Returns:
A
PaymentSyncSummarywith counts of new and updated payments.- Raises:
FfiError – If the node is unreachable.
- Return type:
Example:
summary = wallet.sync_payments() print(f"New: {summary.num_new}, Updated: {summary.num_updated}")
- update_client(client_pk, label=<object object>, clear_label=False, expires_at_ms=<object object>, clear_expiration=False)¶
Update a client’s label or expiration. Omitted fields are left as-is.
- Parameters:
client_pk (str) – Hex-encoded public key of the client to update.
label (object | str | None) – A new label, or
Noneto leave it unchanged.clear_label (bool) – Remove the client’s label. Conflicts with
label.expires_at_ms (object | int | None) – A new expiration (ms since UNIX epoch), or
Noneto leave it unchanged.clear_expiration (bool) – Clear the client’s expiration, so it never expires. Use carefully! Conflicts with
expires_at_ms.
- Returns:
The updated
ClientInfo.- Raises:
FfiError – If
client_pkis malformed, the arguments conflict, or the request fails.- Return type:
ClientInfo
- update_human_bitcoin_address(username)¶
Claim or update the user’s custom Human Bitcoin Address.
Sets this wallet’s Human Bitcoin Address to
₿{username}@lexe.appand its Lightning Address to{username}@lexe.app. Usernames must be 6 to 24 characters of lowercase alphanumerics and hyphens, and must not start with, end with, or contain consecutive hyphens.Claiming requires a total wallet balance of at least 10000 sats. Once claimed, the username can be changed for 24 hours, then is frozen for 90 days.
- Parameters:
username (str) – The username to claim, e.g.
"username"for₿username@lexe.app.- Returns:
A
GetHumanBitcoinAddressResponsewith the new Human Bitcoin Address, the Lightning Address, the BOLT 12 offer that the address resolves to, and whether the username can currently be changed.- Raises:
FfiError – If the username is invalid or taken, the wallet balance is below the minimum, or the username is frozen.
- Return type:
GetHumanBitcoinAddressResponse
Example:
resp = wallet.update_human_bitcoin_address("username") print(resp.human_bitcoin_address)
- update_personal_note(index, personal_note)¶
Update a payment’s personal note.
Call
sync_payments()first so the payment exists locally.- Parameters:
index (str) – Payment index string.
personal_note (str | None) – New personal note text, or
Noneto clear. If provided, it must be non-empty and <= 200 chars / 512 UTF-8 bytes.
- Raises:
FfiError – If the payment doesn’t exist locally.
- Return type:
None
- property user_pk: str¶
Get the user’s hex-encoded public key.
- Returns:
The hex-encoded ed25519 user public key string.
Example:
print(f"User PK: {wallet.user_pk}")
- wait_for_payment(index, timeout_secs=<object object>)¶
Wait for a payment to reach a terminal state (completed or failed) and return the payment information.
Blocks until the payment finalizes or the timeout is reached. A
Nonetimeout waits indefinitely.- Parameters:
index (str) – Payment index string.
timeout_secs (object | int | None) – Maximum wait time in seconds. Waits indefinitely if omitted.
- Returns:
The finalized
Payment.- Raises:
FfiError – If the timeout is exceeded or the node is unreachable.
- Return type:
Example:
resp = wallet.create_invoice(amount_sats=1000) # Wait until someone pays the invoice (or it expires / fails). payment = wallet.wait_for_payment(resp.index) assert payment.status in (PaymentStatus.COMPLETED, PaymentStatus.FAILED)
- withdraw_lnurl(lnurl, amount_sats=<object object>, description=<object object>, personal_note=<object object>)¶
Withdraw an LNURL via the
withdrawRequestflow.Use
analyze()to get the associatedLnurlWithdrawRequest, which contains information on amount constraints, default description, and more.- Parameters:
lnurl (str) – LNURL string to withdraw from.
amount_sats (object | int | None) – Optional amount to withdraw in satoshis. Must satisfy the minimum and maximum limits set by the LNURL endpoint. If
None, the maximum amount is withdrawn.description (object | str | None) – Optional description encoded into the withdrawal invoice and visible to the LNURL endpoint. If
None, the description specified by the LNURL endpoint (if any) is used.personal_note (object | str | None) – Optional private note (not visible to the LNURL endpoint). If provided, it must be non-empty and no longer than 200 chars / 512 UTF-8 bytes.
- Returns:
The resulting
Payment, returned once the withdrawal reaches a terminal state (completed or failed).- Raises:
FfiError – If the LNURL is invalid or initiating the withdrawal fails.
- Return type:
Example:
payment = wallet.withdraw_lnurl(lnurl_string, 1000) print(f"Payment {payment.status}")
- classmethod without_db(env_config, credentials)¶
Create a wallet without local persistence.
Node operations (invoices, payments, node info) work normally. Local payment cache operations (
sync_payments(),list_payments(),clear_payments()) are not available and raise if called.- Parameters:
env_config (WalletConfig) – Wallet environment configuration.
credentials (Credentials) – Authentication credentials (see
Credentials).
- Returns:
A LexeWallet instance without local persistence.
- Raises:
FfiError – If wallet creation fails.
- Return type:
- class lexe.AsyncLexeWallet(*args, **kwargs)¶
Async wallet handle for interacting with a Lexe Lightning node.
For synchronous usage, use
LexeWallet.Example:
from lexe import AsyncLexeWallet, Credentials, RootSeed, WalletConfig config = WalletConfig.mainnet() seed = RootSeed.read(config) creds = Credentials.from_root_seed(seed) wallet = AsyncLexeWallet.load_or_fresh(config, creds) await wallet.signup(seed) await wallet.provision(creds) info = await wallet.node_info() print(f"Balance: {info.balance_sats} sats")
- classmethod fresh(env_config, credentials, lexe_data_dir=<object object>)¶
Create a fresh wallet, deleting any existing local state for this user.
Data for other users and environments is not affected.
- Parameters:
env_config (WalletConfig) – Wallet environment configuration.
credentials (Credentials) – Authentication credentials (see
Credentials).lexe_data_dir (object | str | None) – Base data directory (default:
~/.lexe).
- Returns:
A new AsyncLexeWallet instance.
- Raises:
FfiError – If wallet creation fails.
- Return type:
- classmethod load(env_config, credentials, lexe_data_dir=<object object>)¶
Load an existing wallet from local state.
Raises
LoadWalletError.NotFoundif no local data exists. UseAsyncLexeWallet.fresh()to create local state.- Parameters:
env_config (WalletConfig) – Wallet environment configuration.
credentials (Credentials) – Authentication credentials (see
Credentials).lexe_data_dir (object | str | None) – Base data directory (default:
~/.lexe).
- Returns:
The loaded AsyncLexeWallet instance.
- Raises:
LoadWalletError.NotFound – If no local data exists.
LoadWalletError.LoadFailed – If local data is corrupted.
- Return type:
Example:
try: wallet = AsyncLexeWallet.load(config, creds) except LoadWalletError.NotFound: wallet = AsyncLexeWallet.fresh(config, creds)
- classmethod load_or_fresh(env_config, credentials, lexe_data_dir=<object object>)¶
Load an existing wallet, or create a fresh one if none exists. If you are authenticating with client credentials, this is generally what you want to use.
- Parameters:
env_config (WalletConfig) – Wallet environment configuration.
credentials (Credentials) – Authentication credentials (see
Credentials).lexe_data_dir (object | str | None) – Base data directory (default:
~/.lexe).
- Returns:
An AsyncLexeWallet instance (loaded or newly created).
- Raises:
FfiError – If wallet creation fails.
- Return type:
- classmethod without_db(env_config, credentials)¶
Create a wallet without local persistence.
Node operations (invoices, payments, node info) work normally. Local payment cache operations (
sync_payments(),list_payments(),clear_payments()) are not available and raise if called.- Parameters:
env_config (WalletConfig) – Wallet environment configuration.
credentials (Credentials) – Authentication credentials (see
Credentials).
- Returns:
An AsyncLexeWallet instance without local persistence.
- Raises:
FfiError – If wallet creation fails.
- Return type:
- async analyze(payable)¶
Analyze a Bitcoin or Lightning payment string.
Returns the routes found (as
AnalyzeResponse).payablesholds outbound payment routes, sorted from most to least recommended; eachPayableDetailsincludes the payable string, parsedPaymentMethod, amount constraints, description, and expiration.claimablesholds inbound claim routes (e.g. LNURL-withdraw); eachClaimableDetailsincludes the claimable string, parsedClaimMethod, description, and amount constraints.Supported encodings:
BIP 321 URI:
bitcoin:bc1...Lightning URI:
lightning:ln...BOLT 11 invoice:
lnbc1...BOLT 12 offer:
lno1...Onchain bitcoin address:
bc1...Human Bitcoin Address:
₿username@lexe.appLightning Address:
username@lexe.appLNURL:
lnurl1...orlnurlp://domain.com/path
Within the encodings, the following payment methods are supported:
BOLT 11 invoice
BOLT 12 offer
Bitcoin address
Lightning Address
LNURL-pay
And the following claim methods are supported:
LNURL-withdraw
- Parameters:
payable (str) – The string-encoded payment method.
- Returns:
An
AnalyzeResponsewithpayables(outbound payment routes, sorted from most to least recommended) andclaimables(inbound claim routes, e.g. LNURL-withdraw).- Raises:
FfiError – If no valid payment methods were found.
- Return type:
AnalyzeResponse
Example:
resp = await wallet.analyze("username@lexe.app") details = resp.payables[0] print(details.payable) # "https://lexe.app/.well-known/lnurlp/satoshi" print(details.method) # PaymentMethod.LNURL_PAY(...) print(details.min_amount_sats) # minimum payable amount print(details.max_amount_sats) # maximum payable amount
- async buy_with_cash_app(amount_sats)¶
Buy Bitcoin with Cash App.
Given an amount of Bitcoin that the user wants to buy, returns a Cash App URL that you can redirect your user to complete the purchase. Cash App buys are instant and land directly into Lexe wallet.
- Parameters:
amount_sats (int) – Amount of Bitcoin to buy in satoshis. Must be at least 5000.
- Returns:
A
CashAppBuyResponsewhoseredirect_urlyou should send your user to, to complete the purchase. For the smoothest experience, encourage them to open it on a device where Cash App is already set up.- Raises:
FfiError – If the amount is below the minimum or the request fails.
- Return type:
CashAppBuyResponse
Example:
resp = await wallet.buy_with_cash_app(5000) print(resp.redirect_url) # Redirect your user here
- clear_payments()¶
Clear all locally cached payment data for this wallet.
Clears the local payment cache only. Remote data on the node is not affected. Call
sync_payments()to re-populate.- Raises:
FfiError – If the local database cannot be cleared.
- Return type:
None
- async close_channel(channel_id)¶
Close a Lightning channel.
- Parameters:
channel_id (str) – The id of the channel to close, serialized as a 64-character hex string (32 bytes).
- Raises:
FfiError – If the channel could not be closed.
- Return type:
None
Example:
await wallet.close_channel(channel_id)
- async create_client(expires_at_ms, label=<object object>)¶
Create a new client authorized to control this node.
The returned credentials grant control of this node without exposing the root seed, and can be revoked at any time with
revoke_client().Warning
Anyone with the returned credentials can control this node’s funds. Store them somewhere safe.
- Parameters:
expires_at_ms (int | None) – The client’s expiration (ms since UNIX epoch), or
Nonefor a client that never expires. Use carefully!label (object | str | None) – An optional label of at most 64 UTF-8 bytes.
- Returns:
A
CreateClientResponsewith the new client’s public key and credentials.- Raises:
FfiError – If the request fails.
- Return type:
CreateClientResponse
Example:
# Pass expires_at_ms=None to opt into a never-expiring client. resp = await wallet.create_client(expires_at_ms=None, label="my-server") # Store the credentials somewhere safe; reload later with # ClientCredentials.from_string(...). creds_str = resp.client_credentials.export_string()
- async create_invoice(expiration_secs=<object object>, amount_sats=<object object>, description=<object object>, personal_note=<object object>, partner_pk=<object object>, partner_prop_fee_ppm=<object object>, partner_base_fee_sats=<object object>)¶
Create a BOLT 11 Lightning invoice.
- Parameters:
expiration_secs (object | int | None) – Invoice expiry in seconds (e.g.
3600for 1 hour), orNonefor a default of86400(1 day).amount_sats (object | int | None) – Amount in satoshis, or
Nonefor an amountless invoice.description (object | str | None) – Optional description shown to the payer.
personal_note (object | str | None) – Optional personal note (not visible to the payer). If provided, it must be non-empty and <= 200 chars / 512 UTF-8 bytes.
partner_pk (object | str | None) – Hex-encoded user_pk of a Lexe partner setting custom fees. Must be set for partner fee fields to take effect.
partner_prop_fee_ppm (object | int | None) – Partner proportional fee in parts per million (ppm). Must be set if
partner_pkis set. Min: 5000, Max: 500000 (50%).partner_base_fee_sats (object | int | None) – Partner base fee in satoshis. If set,
amount_satsmust also be set.
- Returns:
A
CreateInvoiceResponsewith the invoice string and metadata.- Raises:
FfiError – If the node is offline or the request fails.
- Return type:
Example:
resp = await wallet.create_invoice(3600, 1000, "Coffee") print(resp.invoice) # BOLT 11 invoice string print(resp.amount_sats) # 1000
- async create_offer(description=<object object>, min_amount_sats=<object object>, expiration_secs=<object object>)¶
Create a BOLT 12 offer to receive Lightning payments.
Unlike invoices, offers are reusable: multiple payments can be made to it, including from multiple payers.
- Parameters:
description (object | str | None) – Optional description shown to the sender when they scan the offer. If provided, it must be non-empty and no longer than 200 chars / 512 UTF-8 bytes.
min_amount_sats (object | int | None) – Optional minimum payment amount in satoshis.
expiration_secs (object | int | None) – Optional expiration time in seconds from now.
- Returns:
A
CreateOfferResponsewith the BOLT 12 offer string.- Raises:
FfiError – If the node is offline or the request fails.
- Return type:
CreateOfferResponse
Example:
resp = await wallet.create_offer(description="Donations") print(resp.offer) # BOLT 12 offer string
- async get_human_bitcoin_address()¶
Get the user’s Human Bitcoin Address.
The Human Bitcoin Address (BIP 353), e.g.
₿username@lexe.app, is a human-readable address which others can pay to send Bitcoin to this wallet. It also works as a Lightning Address (username@lexe.app) for senders which support LNURL but not BIP 353.- Returns:
A
GetHumanBitcoinAddressResponsewith the Human Bitcoin Address, the Lightning Address, the BOLT 12 offer that the address resolves to, and whether the username can currently be changed.- Raises:
FfiError – If the request fails.
- Return type:
GetHumanBitcoinAddressResponse
Example:
resp = await wallet.get_human_bitcoin_address() print(resp.human_bitcoin_address)
- async get_payment(index)¶
Get a specific payment by its index.
- async get_updated_payments(start_index=<object object>, limit=<object object>)¶
Get a batch of payments in ascending
updated_atorder, starting from a givenupdated_atindex.Useful for tailing / syncing payment updates as they occur. Fetches directly from the user node (does not read from or write to the local payments cache).
- Parameters:
start_index (object | str | None) – The cursor at which the results should start, exclusive. If
None, the least recently updated payments will be returned first.limit (object | int | None) – Maximum number of payments to return. Max 100, defaults to 50.
- Returns:
A
GetUpdatedPaymentsResponsewith the updated payments and anupdated_indexcursor for fetching the next page.- Raises:
FfiError – If
start_indexis malformed or the request fails.- Return type:
GetUpdatedPaymentsResponse
Example:
resp = await wallet.get_updated_payments() for p in resp.payments: print(f"{p.index}: {p.status}") # Next page if resp.updated_index is not None: resp = await wallet.get_updated_payments(start_index=resp.updated_index)
- async list_channels()¶
List this node’s Lightning channels.
All of this node’s Lightning channels are connected to the Lexe LSP.
- Returns:
A list of
ChannelDetails.- Raises:
FfiError – If the node is unreachable.
- Return type:
List[ChannelDetails]
Example:
for channel in await wallet.list_channels(): print(f"{channel.channel_id}: {channel.our_balance_sats} sats")
- async list_clients()¶
List the clients authorized to control this node.
Revoked and expired clients are not included.
- Returns:
A dict mapping each client’s hex-encoded public key to its
ClientInfo.- Raises:
FfiError – If the request fails.
- Return type:
dict[str, ClientInfo]
Example:
for pk, client in (await wallet.list_clients()).items(): print(f"{pk}: {client.label}")
- list_payments(filter, order=<object object>, limit=<object object>, after=<object object>)¶
List payments from local storage with cursor-based pagination.
Reads from the local database only (no network calls). Use
sync_payments()to fetch the latest data from the node if needed.- Parameters:
filter (PaymentFilter) – Which payments to include:
PaymentFilter.ALL,PaymentFilter.PENDING,PaymentFilter.COMPLETED,PaymentFilter.FAILED, orPaymentFilter.FINALIZED(completed or failed).order (object | Order | None) – Sort order (
Order.DESCorOrder.ASC). Defaults toDESC(newest first).limit (object | int | None) – Maximum number of payments to return. Defaults to
100.after (object | str | None) – Pagination cursor. Pass
next_indexfrom a previous response to get the next page. Defaults toNone(first page).
- Returns:
A
ListPaymentsResponsewith payments and anext_indexcursor for fetching the next page (Noneif no more results).- Raises:
FfiError – If
afteris not a valid payment index string.- Return type:
Example:
await wallet.sync_payments() # First page resp = wallet.list_payments(PaymentFilter.ALL) for p in resp.payments: print(f"{p.index}: {p.amount_sats} sats ({p.status})") # Next page if resp.next_index is not None: resp = wallet.list_payments(PaymentFilter.ALL, after=resp.next_index)
- async node_info()¶
Get information about the node (balance, channels, version).
- Returns:
A
NodeInfowith the node’s current state.- Raises:
FfiError – If the node is unreachable.
- Return type:
Example:
info = await wallet.node_info() print(f"Balance: {info.balance_sats} sats") print(f"Channels: {info.num_usable_channels}/{info.num_channels}")
- async open_channel(value_sats, user_channel_id=<object object>)¶
Open a Lightning channel from this node to Lexe’s LSP.
- Parameters:
value_sats (int) – The value of the channel to open, in satoshis.
user_channel_id (object | str | None) – An optional idempotency key, serialized as a 32-character hex string (16 bytes). Retrying with the same id won’t open a duplicate channel. A random id is generated if omitted.
- Returns:
An
OpenChannelResponsewith the ids of the newly opened channel.- Raises:
FfiError – If the channel could not be opened.
- Return type:
OpenChannelResponse
Example:
resp = await wallet.open_channel(value_sats=100_000) print(f"Opened channel: {resp.channel_id}")
- async pay(payable, amount_sats=<object object>, message=<object object>, personal_note=<object object>)¶
Pay any string which encodes a Bitcoin or Lightning payment method.
If there are multiple encoded payment methods, the best recommended one is chosen. For finer control, use
analyze()first, then call the specific pay method (pay_invoice(),pay_offer(), etc.).Supported encodings:
BIP 321 URI:
bitcoin:bc1...Lightning URI:
lightning:ln...BOLT 11 invoice:
lnbc1...BOLT 12 offer:
lno1...Onchain bitcoin address:
bc1...Human Bitcoin Address:
₿username@lexe.appLightning Address:
username@lexe.appLNURL:
lnurl1...orlnurlp://domain.com/path
- Parameters:
payable (str) – The string to pay.
amount_sats (object | int | None) – Amount in satoshis to pay. Required if the payable has no encoded amount. If both the payable and
amount_satsspecify an amount, they must match. For LNURL payables, the amount must fall within the receiver’s minimum and maximum range.message (object | str | None) – Optional message to the recipient (BOLT12 offers, LNURL).
personal_note (object | str | None) – Optional personal note (not visible to recipient).
- Returns:
The resulting
Payment, returned once it reaches a terminal state (completed or failed). Exception: onchain sends return immediately with the payment still in a pending state, since on-chain confirmation takes ~1 hour.- Raises:
FfiError – If the payable string is invalid, the amount is missing or out of range, or payment initiation fails.
- Return type:
Example:
payment = await wallet.pay("username@lexe.app", amount_sats=1000) print(f"Payment {payment.status}")
- async pay_invoice(invoice, fallback_amount_sats=<object object>, personal_note=<object object>)¶
Pay a BOLT 11 Lightning invoice.
- Parameters:
invoice (str) – BOLT 11 invoice string to pay.
fallback_amount_sats (object | int | None) – Required if the invoice has no amount encoded.
personal_note (object | str | None) – Optional personal note (not visible to the receiver). If provided, it must be non-empty and <= 200 chars / 512 UTF-8 bytes.
- Returns:
The resulting
Payment, returned once it reaches a terminal state (completed or failed).- Raises:
FfiError – If the invoice is invalid or payment initiation fails.
- Return type:
Example:
payment = await wallet.pay_invoice(bolt11_string) print(f"Payment {payment.status}")
- async pay_lnurl(lnurl, amount_sats, message=<object object>, personal_note=<object object>)¶
Pay an LNURL via the
payRequestflow.Use
analyze()to get the associatedLnurlPayRequest, which contains information on amount constraints, message length limits, and more.- Parameters:
lnurl (str) – LNURL string to pay to.
amount_sats (int) – Amount to pay in satoshis. If the LNURL endpoint specifies a minimum or maximum amount, this value must satisfy those limits.
message (object | str | None) – Optional message visible to the recipient. It is only sent if the LNURL endpoint supports it, and is truncated to the endpoint’s length limit if needed.
personal_note (object | str | None) – Optional personal note (not visible to the receiver). If provided, it must be non-empty and no longer than 200 chars / 512 UTF-8 bytes.
- Returns:
The resulting
Payment, returned once it reaches a terminal state (completed or failed).- Raises:
FfiError – If the LNURL is invalid or payment initiation fails.
- Return type:
Example:
payment = await wallet.pay_lnurl(lnurl_string, 1000) print(f"Payment {payment.status}")
- async pay_offer(offer, amount_sats, message=<object object>, personal_note=<object object>)¶
Pay a BOLT 12 offer over Lightning.
- Parameters:
offer (str) – BOLT 12 offer string to pay.
amount_sats (int) – Amount to pay in satoshis.
message (object | str | None) – Optional message visible to the receiver. If provided, it must be non-empty and no longer than 200 chars / 512 UTF-8 bytes.
personal_note (object | str | None) – Optional personal note (not visible to the receiver). If provided, it must be non-empty and no longer than 200 chars / 512 UTF-8 bytes.
- Returns:
The resulting
Payment, returned once it reaches a terminal state (completed or failed).- Raises:
FfiError – If the offer is invalid or payment initiation fails.
- Return type:
Example:
payment = await wallet.pay_offer(bolt12_offer, 1000) print(f"Payment {payment.status}")
- async provision(credentials)¶
Ensures the wallet is provisioned to all recent trusted releases.
Call every time the wallet is loaded to keep the node running the most up-to-date enclave software.
- Parameters:
credentials (Credentials) – Authentication credentials (see
Credentials).- Raises:
FfiError – If provisioning fails.
- Return type:
None
Example:
wallet = AsyncLexeWallet.load_or_fresh(config, creds) await wallet.provision(creds)
- async revoke_client(client_pk)¶
Permanently revoke a client, making its credentials invalid for authentication. This cannot be undone.
- Parameters:
client_pk (str) – Hex-encoded public key of the client to revoke.
- Returns:
The revoked
ClientInfo.- Raises:
FfiError – If
client_pkis malformed or the request fails.- Return type:
ClientInfo
- async signup(root_seed, partner_pk=<object object>)¶
Register this user with Lexe and provision their node.
Call after creating the wallet for the first time. Idempotent: calling again for an already-signed-up user is safe.
Important
After signup, persist the user’s root seed! Without it, users lose access to their funds permanently.
- Parameters:
root_seed (RootSeed) – The user’s root seed.
partner_pk (object | str | None) – Optional hex-encoded user public key of your company account. Set to earn a share of fees.
- Raises:
FfiError – If signup or provisioning fails.
- Return type:
None
Example:
await wallet.signup(seed) seed.write(config) # Persist seed after signup!
- async sync_payments()¶
Sync payments from the user node to the local payments cache.
Call periodically to keep local payment data up to date.
- Returns:
A
PaymentSyncSummarywith counts of new and updated payments.- Raises:
FfiError – If the node is unreachable.
- Return type:
Example:
summary = await wallet.sync_payments() print(f"New: {summary.num_new}, Updated: {summary.num_updated}")
- async update_client(client_pk, label=<object object>, clear_label=False, expires_at_ms=<object object>, clear_expiration=False)¶
Update a client’s label or expiration. Omitted fields are left as-is.
- Parameters:
client_pk (str) – Hex-encoded public key of the client to update.
label (object | str | None) – A new label, or
Noneto leave it unchanged.clear_label (bool) – Remove the client’s label. Conflicts with
label.expires_at_ms (object | int | None) – A new expiration (ms since UNIX epoch), or
Noneto leave it unchanged.clear_expiration (bool) – Clear the client’s expiration, so it never expires. Use carefully! Conflicts with
expires_at_ms.
- Returns:
The updated
ClientInfo.- Raises:
FfiError – If
client_pkis malformed, the arguments conflict, or the request fails.- Return type:
ClientInfo
- async update_human_bitcoin_address(username)¶
Claim or update the user’s custom Human Bitcoin Address.
Sets this wallet’s Human Bitcoin Address to
₿{username}@lexe.appand its Lightning Address to{username}@lexe.app. Usernames must be 6 to 24 characters of lowercase alphanumerics and hyphens, and must not start with, end with, or contain consecutive hyphens.Claiming requires a total wallet balance of at least 10000 sats. Once claimed, the username can be changed for 24 hours, then is frozen for 90 days.
- Parameters:
username (str) – The username to claim, e.g.
"username"for₿username@lexe.app.- Returns:
A
GetHumanBitcoinAddressResponsewith the new Human Bitcoin Address, the Lightning Address, the BOLT 12 offer that the address resolves to, and whether the username can currently be changed.- Raises:
FfiError – If the username is invalid or taken, the wallet balance is below the minimum, or the username is frozen.
- Return type:
GetHumanBitcoinAddressResponse
Example:
resp = await wallet.update_human_bitcoin_address("username") print(resp.human_bitcoin_address)
- async update_personal_note(index, personal_note)¶
Update a payment’s personal note.
Call
sync_payments()first so the payment exists locally.- Parameters:
index (str) – Payment index string.
personal_note (str | None) – New personal note text, or
Noneto clear. If provided, it must be non-empty and <= 200 chars / 512 UTF-8 bytes.
- Raises:
FfiError – If the payment doesn’t exist locally.
- Return type:
None
- property user_pk: str¶
Get the user’s hex-encoded public key.
- Returns:
The hex-encoded ed25519 user public key string.
Example:
print(f"User PK: {wallet.user_pk}")
- async wait_for_payment(index, timeout_secs=<object object>)¶
Wait for a payment to reach a terminal state (completed or failed) and return the payment information.
Blocks until the payment finalizes or the timeout is reached. A
Nonetimeout waits indefinitely.- Parameters:
index (str) – Payment index string.
timeout_secs (object | int | None) – Maximum wait time in seconds. Waits indefinitely if omitted.
- Returns:
The finalized
Payment.- Raises:
FfiError – If the timeout is exceeded or the node is unreachable.
- Return type:
Example:
resp = await wallet.create_invoice(amount_sats=1000) # Wait until someone pays the invoice (or it expires / fails). payment = await wallet.wait_for_payment(resp.index) assert payment.status in (PaymentStatus.COMPLETED, PaymentStatus.FAILED)
- async withdraw_lnurl(lnurl, amount_sats=<object object>, description=<object object>, personal_note=<object object>)¶
Withdraw an LNURL via the
withdrawRequestflow.Use
analyze()to get the associatedLnurlWithdrawRequest, which contains information on amount constraints, default description, and more.- Parameters:
lnurl (str) – LNURL string to withdraw from.
amount_sats (object | int | None) – Optional amount to withdraw in satoshis. Must satisfy the minimum and maximum limits set by the LNURL endpoint. If
None, the maximum amount is withdrawn.description (object | str | None) – Optional description encoded into the withdrawal invoice and visible to the LNURL endpoint. If
None, the description specified by the LNURL endpoint (if any) is used.personal_note (object | str | None) – Optional private note (not visible to the LNURL endpoint). If provided, it must be non-empty and no longer than 200 chars / 512 UTF-8 bytes.
- Returns:
The resulting
Payment, returned once the withdrawal reaches a terminal state (completed or failed).- Raises:
FfiError – If the LNURL is invalid or initiating the withdrawal fails.
- Return type:
Example:
payment = await wallet.withdraw_lnurl(lnurl_string, 1000) print(f"Payment {payment.status}")
- class lexe.NodeInfo(*, version, measurement, user_pk, node_pk, balance_sats, lightning_balance_sats, lightning_sendable_balance_sats, lightning_max_sendable_balance_sats, onchain_balance_sats, onchain_trusted_balance_sats, num_channels, num_usable_channels)¶
Information about a Lexe Lightning node.
- Parameters:
version (str)
measurement (str)
user_pk (str)
node_pk (str)
balance_sats (int)
lightning_balance_sats (int)
lightning_sendable_balance_sats (int)
lightning_max_sendable_balance_sats (int)
onchain_balance_sats (int)
onchain_trusted_balance_sats (int)
num_channels (int)
num_usable_channels (int)
- version¶
Node’s current semver version, e.g.
"0.6.9".
- measurement¶
Hex-encoded SGX measurement of the current node.
- user_pk¶
Hex-encoded ed25519 user public key.
- node_pk¶
Hex-encoded secp256k1 node public key (“node_id”).
- balance_sats¶
Total balance in sats (Lightning + on-chain).
- lightning_balance_sats¶
Total Lightning balance in sats.
- lightning_sendable_balance_sats¶
Estimated Lightning sendable balance in sats.
- lightning_max_sendable_balance_sats¶
Maximum Lightning sendable balance in sats.
- onchain_balance_sats¶
Total on-chain balance in sats (includes unconfirmed).
- onchain_trusted_balance_sats¶
Trusted on-chain balance in sats.
- num_channels¶
Total number of Lightning channels.
- num_usable_channels¶
Number of usable Lightning channels.
Payments¶
- class lexe.Payment(*, index, rail, kind, direction, hash, preimage, offer_id, txid, amount_sats, fees_sats, partner_pk, partner_prop_fee_ppm, partner_base_fee_sats, status, status_msg, address, invoice, payer_name, message, personal_note, priority, expires_at_ms, finalized_at_ms, created_at_ms, updated_at_ms)¶
Information about a payment.
- Parameters:
index (str)
rail (PaymentRail)
kind (PaymentKind)
direction (PaymentDirection)
hash (Optional[str])
preimage (Optional[str])
offer_id (Optional[str])
txid (Optional[str])
amount_sats (Optional[int])
fees_sats (int)
partner_pk (Optional[str])
partner_prop_fee_ppm (Optional[int])
partner_base_fee_sats (Optional[int])
status (PaymentStatus)
status_msg (str)
address (Optional[str])
invoice (Optional[Invoice])
payer_name (Optional[str])
message (Optional[str])
personal_note (Optional[str])
priority (Optional[ConfirmationPriority])
expires_at_ms (Optional[int])
finalized_at_ms (Optional[int])
created_at_ms (int)
updated_at_ms (int)
- index¶
Unique payment identifier (
<created_at_ms>-<payment_id>).
- rail¶
Technical rail used: onchain, invoice, offer, spontaneous, etc.
- kind¶
Application-level payment kind.
- direction¶
Payment direction: inbound, outbound, or info.
- hash¶
(Lightning only) Hex-encoded payment hash.
- preimage¶
(Lightning only) Hex-encoded payment preimage. Serves as proof-of-payment for outbound. For inbound, only present if the payment succeeded.
- offer_id¶
(Offer payments only) Hex-encoded BOLT12 offer id.
- txid¶
(Onchain only) Hex-encoded Bitcoin txid.
- amount_sats¶
Payment amount in satoshis. For completed inbound invoice payments, this is the amount received. For pending/failed inbound invoice payments, this is the invoice amount (may be
None). For all other payment types, an amount is always present.
- fees_sats¶
Fees for this payment in satoshis. If
partner_pkis set, the partner (not Lexe) determined the fee.
- partner_pk¶
Hex-encoded partner user_pk, if the fees for this payment were set by a Lexe partner instead of using Lexe’s default fees.
- partner_prop_fee_ppm¶
The proportional fee set by the partner, in parts per million (ppm).
- partner_base_fee_sats¶
The base fee set by the partner, in satoshis.
- status¶
Payment status: pending, completed, or failed.
- status_msg¶
Human-readable status message, customized per payment type (e.g. “invoice generated”, “timed out”).
- address¶
(Onchain send only) The address we’re sending to.
- invoice¶
(Invoice payments only) The BOLT 11 invoice.
- payer_name¶
(Offer payments only) Payer’s self-reported name.
- message¶
(Offer/LNURL-pay payments) Payer-provided message.
- personal_note¶
Optional personal note attached to this payment. Can always be added or modified after the payment exists.
- priority¶
(Onchain send only) Confirmation priority used.
- expires_at_ms¶
Invoice or offer expiry time (ms since UNIX epoch), or
Noneif not applicable.
- finalized_at_ms¶
When this payment finalized (ms since UNIX epoch), or
Noneif still pending.
- created_at_ms¶
When this payment was created (ms since UNIX epoch).
- updated_at_ms¶
When this payment was last updated (ms since UNIX epoch).
- class lexe.Invoice(*, string, description, created_at_ms, expires_at_ms, amount_sats, payee_pubkey)¶
A BOLT 11 Lightning invoice.
- Parameters:
string (str)
description (Optional[str])
created_at_ms (int)
expires_at_ms (int)
amount_sats (Optional[int])
payee_pubkey (str)
- string¶
Full bech32-encoded invoice string.
- description¶
Invoice description, if present.
- created_at_ms¶
Creation timestamp (ms since UNIX epoch).
- expires_at_ms¶
Expiration timestamp (ms since UNIX epoch).
- amount_sats¶
Amount in satoshis, if specified.
- payee_pubkey¶
Hex-encoded payee node public key.
- class lexe.PaymentSyncSummary(*, num_new, num_updated)¶
Summary of a payment sync operation.
- Parameters:
num_new (int)
num_updated (int)
- num_new¶
Number of new payments added to the local DB.
- num_updated¶
Number of existing payments that were updated.
- class lexe.ListPaymentsResponse(*, payments, next_index)¶
Response from listing payments.
- Parameters:
payments (List[Payment])
next_index (Optional[str])
- payments¶
Payments in the requested page.
- next_index¶
Cursor for fetching the next page, or
Noneif there are no more results.
- class lexe.CreateInvoiceResponse(*, index, invoice, description, amount_sats, created_at_ms, expires_at_ms, payment_hash, payment_secret)¶
Response from creating a Lightning invoice.
- Parameters:
index (str)
invoice (str)
description (Optional[str])
amount_sats (Optional[int])
created_at_ms (int)
expires_at_ms (int)
payment_hash (str)
payment_secret (str)
- index¶
Unique payment identifier for this invoice.
- invoice¶
BOLT 11 invoice string.
- description¶
Description encoded in the invoice, if provided.
- amount_sats¶
Amount in satoshis, if specified.
- created_at_ms¶
Invoice creation time (ms since UNIX epoch).
- expires_at_ms¶
Invoice expiration time (ms since UNIX epoch).
- payment_hash¶
Hex-encoded payment hash.
- payment_secret¶
Payment secret.
Payment Enums¶
- class lexe.PaymentDirection(*values)¶
Direction of a payment relative to this wallet.
INBOUND – Incoming payment (receiving funds).
OUTBOUND – Outgoing payment (sending funds).
INFO – Informational (e.g. channel open/close events).
- INBOUND = 0¶
Incoming payment.
- OUTBOUND = 1¶
Outgoing payment.
- INFO = 2¶
Informational payment.
- class lexe.PaymentStatus(*values)¶
Status of a payment.
PENDING – Payment is in progress.
COMPLETED – Payment completed successfully.
FAILED – Payment failed.
- PENDING = 0¶
Payment is pending.
- COMPLETED = 1¶
Payment completed successfully.
- FAILED = 2¶
Payment failed.
- class lexe.PaymentFilter(*values)¶
Filter for listing payments.
ALL – Include all payments.
PENDING – Only pending payments.
COMPLETED – Only completed payments.
FAILED – Only failed payments.
FINALIZED – Only finalized payments (completed or failed).
- ALL = 0¶
Include all payments.
- PENDING = 1¶
Include only pending payments.
- COMPLETED = 2¶
Include only completed payments.
- FAILED = 3¶
Include only failed payments.
- FINALIZED = 4¶
Include only finalized payments (completed or failed).
- class lexe.PaymentKind¶
Application-level kind for a payment.
ONCHAIN – On-chain Bitcoin payment.
INVOICE – Lightning BOLT 11 invoice payment.
OFFER – Lightning BOLT 12 offer payment.
SPONTANEOUS – Spontaneous (keysend) Lightning payment.
WAIVED_CHANNEL_FEE – Waived channel fee.
WAIVED_LIQUIDITY_FEE – Waived liquidity fee.
BUY_CASH_APP – A buy funded via Cash App.
LIGHTNING_ADDRESS – A payment to or from a Lightning Address.
HUMAN_BITCOIN_ADDRESS – A payment to or from a BIP353 Human Bitcoin Address.
UNKNOWN – Unknown kind from a newer node version.
- ONCHAIN¶
alias of
ONCHAIN
- INVOICE¶
alias of
INVOICE
- OFFER¶
alias of
OFFER
- SPONTANEOUS¶
alias of
SPONTANEOUS
- WAIVED_CHANNEL_FEE¶
alias of
WAIVED_CHANNEL_FEE
- WAIVED_LIQUIDITY_FEE¶
alias of
WAIVED_LIQUIDITY_FEE
- BUY_CASH_APP¶
alias of
BUY_CASH_APP
- LIGHTNING_ADDRESS¶
alias of
LIGHTNING_ADDRESS
- HUMAN_BITCOIN_ADDRESS¶
alias of
HUMAN_BITCOIN_ADDRESS
- UNKNOWN¶
alias of
UNKNOWN
- class lexe.PaymentRail(*values)¶
Technical rail used to fulfill a payment.
ONCHAIN – On-chain Bitcoin transaction.
INVOICE – Lightning BOLT 11 invoice.
OFFER – Lightning BOLT 12 offer.
SPONTANEOUS – Spontaneous (keysend) Lightning payment.
WAIVED_FEE – Internal waived fee.
UNKNOWN – Unknown rail from a newer node version.
- ONCHAIN = 0¶
On-chain Bitcoin payment.
- INVOICE = 1¶
Lightning invoice payment.
- OFFER = 2¶
Lightning offer payment.
- SPONTANEOUS = 3¶
Spontaneous Lightning payment.
- WAIVED_FEE = 4¶
Waived fee payment.
- UNKNOWN = 5¶
Unknown rail from a newer version of node.
- class lexe.ConfirmationPriority(*values)¶
Confirmation priority for on-chain Bitcoin transactions.
HIGH – Fastest confirmation (highest fees).
NORMAL – Standard confirmation target.
BACKGROUND – Lowest fees (slowest confirmation).
- HIGH = 0¶
Fastest confirmation (highest fees).
- NORMAL = 1¶
Standard confirmation target.
- BACKGROUND = 2¶
Lowest fees (slowest confirmation).
Functions¶
- lexe.default_lexe_data_dir()¶
Returns the default Lexe data directory (
~/.lexe).- Returns:
The absolute path to the default data directory.
- Raises:
FfiError – If the home directory cannot be determined.
- Return type:
str
Example:
data_dir = default_lexe_data_dir() # '/home/user/.lexe'
- lexe.init_logger(default_level='info')¶
Initialize the Lexe logger with the given default log level.
Call once at startup to enable logging.
- Parameters:
default_level (str) – Log level string. One of
"trace","debug","info","warn","error". Defaults to"info".- Return type:
None
Example:
init_logger()
Errors¶
- class lexe.SeedFileError¶
Error type for seedphrase file operations.
Raised by
RootSeed()file I/O methods (read(),read_from_path(),write(),write_to_path()).Variants:
NotFound – Seedphrase file not found. Attributes:
path.ParseError – Failed to parse the seedphrase. Attributes:
message.AlreadyExists – Seedphrase file already exists. Attributes:
path.IoError – I/O error during the file operation. Attributes:
message.
Example:
try: seed = RootSeed.read_from_path(path) except SeedFileError.NotFound as e: print(f"No seed at {e.path}") except SeedFileError.ParseError as e: print(f"Bad seed: {e.message}")
- exception NotFound(path)¶
The seedphrase file was not found at the given path.
- exception ParseError(message)¶
The seedphrase file could not be parsed (e.g. invalid mnemonic).
- exception AlreadyExists(path)¶
A seedphrase file already exists at the given path.
- exception IoError(message)¶
An I/O error occurred during the file operation.
- class lexe.LoadWalletError¶
Error type for wallet loading operations.
Raised by
LexeWallet.load()andAsyncLexeWallet.load().Variants:
NotFound – No local wallet data found for this user/environment.
LoadFailed – Failed to load the wallet. Attributes:
message.
Example:
try: wallet = LexeWallet.load(config, creds) except LoadWalletError.NotFound: wallet = LexeWallet.fresh(config, creds) except LoadWalletError.LoadFailed as e: print(f"Load failed: {e.message}")
- exception NotFound¶
No local wallet data exists for this user and environment.
- exception LoadFailed(message)¶
Failed to load the wallet (e.g. corrupted data, invalid seed).
- class lexe.FfiError(*args, **kwargs)¶
Error type raised by SDK methods.
Catch this to handle Lexe SDK errors.
- message()¶
Returns the error message string.
- Return type:
str
Example:
try: info = wallet.node_info() except FfiError as e: print(f"SDK error: {e.message()}")
- message()¶
Returns the error message string.
- Returns:
A human-readable description of the error.
- Return type:
str