TypeScript SDK reference

This reference distinguishes exported utilities from legacy contract wrappers. Package availability and setup are covered in installation. Amount calculations use USDC base units as bigint, where 1_000_000n is 1 USDC.

Exact amounts and fees#

ExportBehavior
calcFee(amount, customRateBps?)Current retail/enterprise fee arithmetic (RETAIL_FEE_BPS, RETAIL_FEE_CAP_6D)
estimateFee(merchant, amount, publicClient)Reads current on-chain calculateFee(address,uint256) and returns { fee, net } as bigints
calculateProtocolFee(amount, feeBps, feeCapAmount)Generic capped fee helper; caller supplies rate and cap
calculateReferrerFee(amount, refBps)Integer proportional fee helper
splitFees(grossAmount, feeBps, refBps, feeCapAmount)Returns { netAmount, protocolFee, refFee } using the generic helpers
parseUSDC(text) / formatUSDC(amount)Convenience helpers using JavaScript floating-point numbers; not arbitrary-precision accounting primitives

calcFee without a positive supported override uses retail pricing: RETAIL_FEE_BPS (50 basis points, 0.5%), capped at RETAIL_FEE_CAP_6D (50_000_000n, 50 USDC). Both constants are exported. A valid integer override from 1 through 50 basis points uses the enterprise formula without a cap. Zero, omitted, invalid, or above-50 overrides fall back to retail, mirroring the registry's clamp. In particular, an explicit 50 enterprise override is uncapped and is not equivalent to the default retail schedule. These values match registry 1.4.0 and later.

This offline example can run after installation:

javascript
import { calcFee } from '@cleared/sdk';

const amount = 100_000_000_000n; // 100,000 USDC
const retail = calcFee(amount); // capped at 50 USDC
const enterprise20bps = calcFee(amount, 20); // uncapped
const enterprise50bps = calcFee(amount, 50); // uncapped, at the ceiling
const outOfRange = calcFee(amount, 51); // above the ceiling: falls back to retail
if (
  retail !== 50_000_000n ||
  enterprise20bps !== 200_000_000n ||
  enterprise50bps !== 500_000_000n ||
  outOfRange !== retail
)
  throw new Error('Unexpected fee');
console.log([retail, enterprise20bps, enterprise50bps, outOfRange].map(String));

For an unpaid invoice, use estimateFee with the actual merchant Safe and correctly configured public client if a current fee preview is needed. For a paid invoice, use its recorded settlement fee, not today's merchant rate. Generic splitFees does not discover an enterprise rate, and its referrer arithmetic must not be mistaken for the current merchant-fee policy. See fees.

For arbitrary decimal inputs, validate the string and convert without a JavaScript number intermediary. With the workspace's viem dependency:

javascript
import { parseUnits, formatUnits } from 'viem';

const input = '123456789012.123456';
if (!/^\d+(\.\d{1,6})?$/.test(input)) throw new Error('Use at most six decimals');
const amount = parseUnits(input, 6);
if (amount !== 123456789012123456n) throw new Error('Precision loss');
console.log(formatUnits(amount, 6));

Reject more than six decimal places instead of silently rounding. Serialize bigints to decimal strings for JSON. parseUSDC uses parseFloat and rounding; formatUSDC converts to Number and two decimal places. Neither should be used to round-trip exact raw amounts.

Hash and display utilities#

ExportContract
canonicalizeInvoice(object)Sorts top-level JSON keys, then serializes the object
computeMetaHash(object)Keccak-256 of UTF-8 canonicalized JSON
verifyMetaHash(object, expectedHash)Case-insensitive comparison of computed and expected hex hash
computeCustomerHash(customerId)Removes UUID hyphens, lowercases, validates 16 bytes of hex, then hashes those bytes with Keccak-256
ZERO_CUSTOMER_HASHZero bytes32 for no linked customer
customerHashToBuffer(hash), bufferToCustomerHash(buffer)Node/Bun Buffer conversion helpers; zero/null represents no customer
formatInvoiceNumber(number, timestamp?)Display label from a sequential number and optional Unix-second timestamp; zero yields null
parseFormattedInvoiceNumber(text)Parses display year/number, does not resolve an on-chain invoice ID
isLegacyInvoice(number)Tests for zero sequential number
initialsFromName(name)Display initials helper

Canonicalization sorts only the top-level keys; it is not a recursive JSON canonicalization standard. Preserve nested structure/order and verify against the on-chain anchor. Hashing an arbitrary reshaped metadata object can produce a different hash. Keep the pay page's verification intact. HMAC request signing is a separate algorithm over raw request bytes, not this metadata canonicalization.

Invoice display formatting uses JavaScript numeric conversion and is not an arbitrary-precision identifier transformation. Preserve raw IDs/numbers separately for storage and reconciliation.

Client construction#

ClearedSDK exposes invoices and allowances objects and accepts (config, publicClient, walletClient?). ClearedConfig contains chainId, rpcUrl, and addresses. Factory methods are create(config, account?), createLocal(addresses?, account?), and createBaseSepolia(addresses?, account?).

Supporting exports include getChainById, LOCAL_CHAIN, createClearedPublicClient, and createClearedWalletClient. Recognized chain IDs are 8453 (Base), 84532 (Base Sepolia), and 31337 (local). Use getSDKAddresses(chainId) from @cleared/addresses for compatible address configuration. Presence of an allowanceVault configuration field does not establish a supported deployed allowance service.

Passing an account address to the HTTP wallet factory does not import a private key or create a signer. It relies on a transport capable of signing for that account. Ordinary public RPC endpoints do not provide that authority. Supplying a wallet client is not permission to skip the contract compatibility checks below.

Contract-wrapper compatibility#

Exported methodCurrent integration status
invoices.issue(params)Direct contract issuance wrapper. Requires a correctly authorized wallet client and caller-provided metadata anchors. It does not create REST customers, encrypt metadata, generate access tokens, activate a server signer, or provide REST idempotency. Prefer REST /invoices/issue for the hosted invoicing workflow.
invoices.getInvoice(id)Legacy incompatible tuple ABI. Current registry returns agent, merchant, token, amount, dueAt, settledAt, and quoteId; the wrapper expects a different tuple including status and metadata fields. Use REST reads or a current ABI.
invoices.buildSettleTypedData(...)Legacy authorization model. Do not use it as current payment signing data.
invoices.settleWithAuth(id, deadline, signature)Legacy incompatible signature. Current contract expects two transfer-authorization structs, not (id, deadline, v, r, s).
invoices.settleFromVault(id, projectId)Legacy vault flow absent from the current registry surface. Do not integrate as an available payment method.
allowances.createOrFund, getAllowance, releaseUnused, pause, unpauseLegacy/deferred allowance-vault wrappers, not a current supported invoicing/payment service.

The exported InvoiceStatus enum maps Issued=0, Paid=1, and Canceled=2, but that does not fix the legacy wrapper's response ABI. No cancel, sessions, REST customer management, HMAC client, or webhook verification method is exported by this SDK. Use REST, MCP, or the dashboard for those supported workflows, and review known limitations.