Docs
TypeScript SDK
Reference for @noir-wallet/agent-sdk: reads, payment checks, tap-to-pay, owner operations, events and signers.
npm install @noir-wallet/agent-sdk @stellar/stellar-sdkWorks in Node 20+, browsers and React Native. Secret keys never pass through the SDK unless you choose keypairSigner on a server.
Create a client
import { NoirAgentClient, TESTNET } from '@noir-wallet/agent-sdk'
const noir = new NoirAgentClient() // Noir on Testnet
const viaMyRpc = new NoirAgentClient({ rpcUrl: 'https://my-rpc.example' })
const myDeploy = new NoirAgentClient({ network: {
rpcUrl, networkPassphrase, contracts: { deviceRegistry, agentRegistry, paymentEscrow },
} })Reads
| Method | Returns | Notes |
|---|---|---|
getPolicy(deviceHash) | NoirAgentPolicy | null | Agent, maxAmount, asset, expiresAt |
getDeviceOwner(deviceHash) | string | null | Owner wallet address |
listDevices(wallet) | string[] | Device hashes registered to a wallet |
getEscrowBalance(deviceHash) | bigint | Escrowed amount, smallest unit |
getPendingBalance(merchant) | bigint | What the merchant can claim |
checkPayment({ deviceHash, agent, asset, amount }) | PaymentCheck | { ok } or { ok: false, reason } |
checkPayment asks the contract’s own check_payment, so it can never disagree with what authorize enforces. Refusal reasons: no_agent, wrong_agent, wrong_asset, invalid_amount, over_limit, expired, insufficient_escrow.
Signers
Writes take a NoirSigner: any object with publicKey and signTransaction(xdr, { networkPassphrase }) — the Freighter / Stellar Wallets Kit shape.
import { keypairSigner } from '@noir-wallet/agent-sdk'
const agent = keypairSigner(process.env.AGENT_SECRET!) // server-side agent
const merchant = walletKitSigner // a connected browser walletTap-to-pay and claim
const { hash, nonce } = await noir.authorizePayment({
agent, deviceHash, merchant: merchantAddress, asset, amount: 10_000_000n,
})
// later, in batch:
await noir.claim({ merchant, token: asset })nonce must strictly increase per device and agent; the default (milliseconds since epoch) does. Refusals throw NoirContractError with the contract’s error name, e.g. AgentNotAuthorized, InsufficientBalance, DuplicateAuth.
Every operation
execute(signer, op) runs any write. The signer is the acting account:
op.kind | Signer | Fields |
|---|---|---|
authorize | agent | deviceHash, merchant, asset, amount, nonce |
claim | merchant | token |
registerAgent | owner | deviceHash, agent, asset, maxAmount, expiresAt? |
revokeAgent | owner | deviceHash |
fundEscrow | owner | deviceHash, token, amount |
defundEscrow | owner | deviceHash, token, amount |
await noir.execute(ownerWallet, {
kind: 'registerAgent', deviceHash, agent: agentAddress, asset,
maxAmount: 50_000_000n, expiresAt: new Date('2027-01-01'),
})
await noir.execute(ownerWallet, { kind: 'fundEscrow', deviceHash, token: asset, amount: 100_000_000n })Sign somewhere else
const unsignedXdr = await noir.prepare(sourceAddress, op) // simulated, fees and footprint set
const signedXdr = await hardwareWallet.sign(unsignedXdr)
const hash = await noir.submit(signedXdr) // resolves once confirmedEvents
const stop = noir.watch({
types: ['payment.authorized'],
merchant: merchantAddress,
onEvent: (e) => markOrderPaid(e.txHash, e.amount),
})
const page = await noir.getEvents({ startLedger }) // or { cursor }
const all = await noir.pastEvents(latestLedger - 17_000) // RPC keeps about 7 daysEvent types and the webhook relay are covered in Webhooks & events.