Work directly with the client.
Use the shared browser client for subscriptions, deposits, inference access, and mutual withdrawals.
On this page
Client lifecycle
purseClient() returns the shared client. Register the provider before a wallet operation. Initialize in browser code; ensureReady() is the strict readiness check and throws if the SDK cannot boot.
import { purseClient } from "@openzk.app/purse";
const client = purseClient();
client.setWalletProvider(provider);
await client.init();
const health = client.getHealth();
const snapshot = client.getSnapshot();init() checks operator health and attempts SDK startup. It catches SDK readiness failures, so a resolved initialization does not by itself prove that the worker is ready.
State subscriptions
Read a snapshot, then subscribe to changes. Both subscription methods return a cleanup function.
const unsubscribe = client.subscribe(() => {
const snapshot = client.getSnapshot();
console.log(snapshot.status, snapshot.balanceGwei.toString());
});
const unsubscribeHealth = client.subscribeHealth(() => {
console.log(client.getHealth().status);
});
// Clean up when your view unmounts.
unsubscribe();
unsubscribeHealth();| Field | Type / meaning |
|---|---|
balanceGwei | bigint · remaining private balance. |
status | synced, syncing, stale, or unfunded. |
latestRoot | Current root string. |
noteFingerprint | Display identifier, or null when no note is installed. |
anchorTimestamp / expiresAt | State anchor and optional expiry. |
Convert bigint values to strings before JSON serialization. Use getJournal() for the locally assembled payment history.
Deposits
The low-level quote method accepts a USD amount as a string. The deposit method takes the ETH amount returned by that quote, the account address, and a status callback.
const quote = await client.requestDepositQuote("5.00");
await client.startDeposit(quote.ethAmount, address, (phase) => {
console.log(phase);
});Inference access
Acquire a session with a spending limit, use the leased access for inference, then release and settle it. The example uses the exported streaming helper so the request stays within the lease’s completion limit.
import { purseClient, streamOpenRouterInference } from "@openzk.app/purse";
const client = purseClient();
const sessionId = "openzk_" + crypto.randomUUID();
const access = await client.acquireAccess(sessionId, model.tierUsd, (progress) => {
console.log(progress.phase);
});
try {
await streamOpenRouterInference({
access,
model: model.id,
prompt: "Explain private payments.",
onToken: (token) => console.log(token),
});
} finally {
access.release();
await client.settleLease();
}access supplies the inference URL, request headers, and spending limit. Keep these session credentials out of logs and public application state.
Withdrawals
await client.withdrawMutual(recipientAddress, (phase) => {
console.log(phase);
});A withdrawal closes the private note back to an Ethereum destination. Read the refreshed snapshot after completion instead of treating a displayed estimate as the settled balance.
Display helpers
import { gweiToEth, formatEth, shortenFingerprint,
getErrorCatalogEntry } from "@openzk.app/purse";
const snapshot = client.getSnapshot();
const balance = formatEth(gweiToEth(snapshot.balanceGwei));
const fingerprint = shortenFingerprint(snapshot.noteFingerprint);
const message = getErrorCatalogEntry("stale_root").userMessage;client.formatMoney(gwei) is asynchronous and uses the SDK’s conversion. The root exports also include money, time, model-catalog, and single-retry helpers.
Documentation for the OpenZK browser toolkit. Report a documentation issue ↗