Build
API reference
Every public export of @umbr/sdk, its arguments and what it returns. The API is a preview and may change before the first release.
- Package
- @umbr/sdk
- Status
- Preview
- Amounts
- Decimal strings
Preview
Conventions: every amount is a decimal string in the asset's units ("40.00"), assets are named by symbol ("pathUSD", "USDG"), and every method that writes returns once the transaction is included. Failures throw an UmbrError.
Import#
import {
createUmbrClient,
verifyProof,
networks,
fileStore,
UmbrError,
} from "@umbr/sdk";
import type { Proof, VerifyResult, Note, PayrollLine, ClientOptions, NoteStore } from "@umbr/sdk";fileStore(path) returns a NoteStore that writes to a folder, for Node. In browsers the default store is IndexedDB.
createUmbrClient#
function createUmbrClient(options: ClientOptions): UmbrClient;| Name | Type | Notes |
|---|---|---|
network | Network | Required. One of networks. |
wallet | WalletClient | A viem wallet. Use in browsers. Pass this or signer. |
signer | 0x${string} | A private key. Server and agent code only, read from a secret store. |
relayer | "default" | string | false | Optional. A custom relayer URL, or false to submit from your own wallet. Default "default". |
limits | { perPayment?, perDay? } | Optional hard caps, checked before any proof is made. |
storage | NoteStore | Optional. Defaults to IndexedDB in browsers and fileStore("./.umbr") in Node. |
Returns an UmbrClient. Its address property is your private receive address (umbr1q...), derived locally from the wallet or signer.
const umbr = createUmbrClient({
network: networks.tempoModerato,
wallet, // browser
relayer: "default",
limits: { perPayment: "2.00", perDay: "50.00" },
});
umbr.address; // "umbr1qexample...you"networks#
const networks: {
tempoModerato: Network; // Tempo testnet, chain id 42431
robinhoodTestnet: Network; // Robinhood Chain testnet, chain id 46630
tempo: Network; // chain id 4217, usable only once configured
robinhood: Network; // chain id 4663, usable only once configured
};Each Network has chainId, name, assets and configured. A network is configured only when its pool address and start block are set; otherwise writes throw POOL_NOT_CONFIGURED. Mainnet entries are not configured today. See Networks.
const { chainId, assets, configured } = networks.robinhoodTestnet;
// 46630, ["USDG"], true when NEXT_PUBLIC_UMBR_POOL_46630 and its start block are setumbr.shield#
umbr.shield(args: { asset: string; amount: string }): Promise<{ txHash: `0x${string}`; notes: Note[] }>;| Name | Type | Notes |
|---|---|---|
asset | string | Symbol of a supported stablecoin on the client's network. |
amount | string | How much public balance to move in. Approves the pool first if needed. |
Returns the deposit txHash and the new notes. Shielding is visible on chain: the explorer shows your public address depositing this amount.
const { txHash, notes } = await umbr.shield({ asset: "pathUSD", amount: "250.00" });umbr.send#
umbr.send(args: {
to: string; // "umbr1q..."
asset: string;
amount: string;
memo?: string;
}): Promise<{ txHash: `0x${string}`; paymentId: string }>;| Name | Type | Notes |
|---|---|---|
to | string | The recipient's umbr1q... address. A 0x address throws. |
asset | string | Asset to pay in. |
amount | string | Checked against limits first. |
memo | string? | Optional note encrypted for the recipient only. |
Returns txHash and a paymentId you can later pass to umbr.prove.
const { paymentId } = await umbr.send({
to: "umbr1qexample...ana",
asset: "pathUSD",
amount: "40.00",
memo: "Invoice 0192",
});umbr.links
Claim links pay someone who has no UMBR address yet. create locks the amount; anyone holding the link can claim it until it expires; revoke returns unclaimed funds to you.
umbr.links.create(args: { asset: string; amount: string; expiresIn: "1d" | "7d" | "30d" }): Promise<{ url: string; id: string }>;
umbr.links.claim(url: string): Promise<{ txHash: `0x${string}` }>;
umbr.links.revoke(id: string): Promise<{ txHash: `0x${string}` }>;umbr.unshield#
umbr.unshield(args: { asset: string; amount: string; to: `0x${string}` }): Promise<{ txHash: `0x${string}` }>;| Name | Type | Notes |
|---|---|---|
asset | string | Asset to withdraw. |
amount | string | Checked against limits first. |
to | 0x${string} | Public destination. Bound inside the proof, so a relayer cannot change it. |
Returns txHash. The withdrawal amount and destination are public.
await umbr.unshield({ asset: "pathUSD", amount: "60.00", to: "0xYourPublicWallet" });umbr.balance#
umbr.balance(asset: string): Promise<string>;
umbr.balances(): Promise<Record<string, string>>;| Name | Type | Notes |
|---|---|---|
asset | string | Symbol to total. Unknown symbols throw. |
Returns the sum of unspent notes as a decimal string. balances() returns every asset on the network. Both read the local note store; call notes.sync() first for fresh numbers.
await umbr.balance("pathUSD"); // "210.00"
await umbr.balances(); // { pathUSD: "210.00", AlphaUSD: "0.00" }umbr.notes#
umbr.notes.sync(): Promise<void>;
umbr.notes.list(filter?: { asset?: string }): Promise<Note[]>;
umbr.on(event: "payment", handler: (p: IncomingPayment) => void): () => void;| Name | Type | Notes |
|---|---|---|
filter.asset | string? | Optional. Only notes in this asset. |
event | "payment" | Fires during sync for each newly found incoming payment. |
handler | (p) => void | Receives { paymentId, asset, amount, memo, from: undefined }. |
Returns: sync resolves when the store is up to date with the pool; list returns Note[], spent ones included; on returns an unsubscribe function.
const off = umbr.on("payment", (p) => console.log(p.amount, p.asset, p.memo));
await umbr.notes.sync();
const notes = await umbr.notes.list({ asset: "pathUSD" });
off(); // stop listeningumbr.payroll#
umbr.payroll.run(args: { asset: string; lines: PayrollLine[] }): Promise<{
id: string;
txHashes: `0x${string}`[];
lines: (PayrollLine & { status: "settled" | "failed" })[];
}>;
umbr.payroll.parseCsv(text: string): PayrollLine[];
umbr.payroll.schedule(args: {
asset: string;
lines: PayrollLine[];
every: "week" | "month";
startAt: string | Date;
}): Promise<{ id: string }>;| Name | Type | Notes |
|---|---|---|
asset | string | One asset per run. |
lines | PayrollLine[] | Recipients and amounts. The whole run counts towards limits. |
text | string | CSV with columns address,amount and an optional label. A header row is allowed. |
every | "week" | "month" | Schedule interval. |
startAt | string | Date | First run time, ISO 8601 when a string. |
Returns: run gives the run id, every txHash and the status of each line; parseCsv gives lines and throws on a malformed row; schedule gives a schedule id.
const lines = umbr.payroll.parseCsv(`address,amount,label
umbr1qexample...ana,4200.00,Design
umbr1qexample...ben,3850.00,Support`);
const run = await umbr.payroll.run({ asset: "USDG", lines });umbr.prove#
umbr.prove(args: {
claim: "balance-exact" | "balance-at-least" | "payment" | "payroll-total";
asset?: string;
amount?: string;
payment?: string; // paymentId, for claim "payment"
run?: string; // run id, for claim "payroll-total"
reveal?: "exact" | "at-least"; // for claim "payment"
audience: string;
expiresIn: "1d" | "7d" | "30d";
}): Promise<Proof>;| Name | Type | Notes |
|---|---|---|
claim | string | Which of the four proofs to make. |
asset | string? | Required for balance claims. |
amount | string? | The floor for at-least and for a payment with reveal: "at-least". |
payment | string? | A paymentId from send or a payment event. |
run | string? | A payroll run id you sent. |
reveal | "exact" | "at-least" | Payment proofs only. Default "exact". |
audience | string | Who the proof is for. Bound into the proof. |
expiresIn | "1d" | "7d" | "30d" | Bound into the proof. |
Returns a Proof. Proving runs locally and never touches the chain.
const proof = await umbr.prove({
claim: "payment",
payment: paymentId,
reveal: "at-least",
amount: "300.00",
audience: "Northwind Leasing",
expiresIn: "7d",
});
proof.link; // a /verify link you can shareverifyProof#
function verifyProof(input: Proof | string, options?: { network?: Network }): Promise<VerifyResult>;| Name | Type | Notes |
|---|---|---|
input | Proof | string | A Proof object, its JSON, or a /verify link. |
options.network | Network? | Optional. Otherwise read from the proof. |
Returns a VerifyResult. An invalid proof resolves with valid: false rather than throwing; only malformed input throws. Needs no wallet.
const result = await verifyProof(pastedJsonOrLink);
if (!result.valid || result.expired) reject();
else accept(result.statement, result.audience);Errors#
Every failure the SDK expects is an UmbrError with a stable code and a readable message.
| Code | When |
|---|---|
LIMIT_EXCEEDED | A send, unshield, link or payroll run would go over perPayment or perDay. Raised before any proof is made. |
INSUFFICIENT_PRIVATE_BALANCE | Your unspent notes in that asset do not cover the amount (plus relayer fee). |
POOL_NOT_CONFIGURED | The network has no pool address or start block set, so it is read-only. |
PROOF_FAILED | Proof generation failed, usually from stale notes. Sync and try again. |
RELAYER_REJECTED | The relayer refused or could not submit the transaction. Nothing was spent. |
UNKNOWN_ROOT | A proof refers to a Merkle root the pool has not recorded. |
PROOF_EXPIRED | A disclosure proof is past its expiry. |
NETWORK_MISMATCH | The wallet, address or proof belongs to a different chain than the client. |
import { UmbrError } from "@umbr/sdk";
try {
await umbr.send({ to, asset: "pathUSD", amount: "75.00" });
} catch (err) {
if (!(err instanceof UmbrError)) throw err;
switch (err.code) {
case "INSUFFICIENT_PRIVATE_BALANCE": return askToShield();
case "RELAYER_REJECTED": return retryWithoutRelayer();
default: throw err;
}
}Types#
type Proof = {
format: "umbr.disclosure/1";
claim: "balance-exact" | "balance-at-least" | "payment" | "payroll-total";
json: string; // the full proof (format "umbr.disclosure/1"), safe to send to the reader
text: string; // the same proof as one line: "umbrproof1:" + base64url(json)
link: string; // https://umbr.trade/verify#... with the proof embedded
};
type VerifyResult = {
valid: boolean;
claim: Proof["claim"];
statement: string; // e.g. "Holds at least 1,000.00 pathUSD"
audience: string;
expiresAt: Date;
expired: boolean;
};
type Note = {
commitment: `0x${string}`;
asset: string;
amount: string;
spent: boolean;
createdAt: Date;
};
type PayrollLine = {
to: string; // "umbr1q..."
amount: string;
label?: string; // stays on your device
};
type ClientOptions = {
network: Network;
wallet?: WalletClient; // viem, for browsers
signer?: `0x${string}`; // private key, for servers and agents only
relayer?: "default" | string | false;
limits?: { perPayment?: string; perDay?: string };
storage?: NoteStore;
};
interface NoteStore {
get(key: string): Promise<string | undefined>;
set(key: string, value: string): Promise<void>;
delete(key: string): Promise<void>;
keys(prefix?: string): Promise<string[]>;
}