Docs

TypeScript SDK

Reference for @noir-wallet/agent-sdk: reads, payment checks, tap-to-pay, owner operations, events and signers.

bash
npm install @noir-wallet/agent-sdk @stellar/stellar-sdk

Works in Node 20+, browsers and React Native. Secret keys never pass through the SDK unless you choose keypairSigner on a server.

Create a client

ts
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

MethodReturnsNotes
getPolicy(deviceHash)NoirAgentPolicy | nullAgent, maxAmount, asset, expiresAt
getDeviceOwner(deviceHash)string | nullOwner wallet address
listDevices(wallet)string[]Device hashes registered to a wallet
getEscrowBalance(deviceHash)bigintEscrowed amount, smallest unit
getPendingBalance(merchant)bigintWhat 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.

ts
import { keypairSigner } from '@noir-wallet/agent-sdk'

const agent = keypairSigner(process.env.AGENT_SECRET!)   // server-side agent
const merchant = walletKitSigner                         // a connected browser wallet

Tap-to-pay and claim

ts
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.kindSignerFields
authorizeagentdeviceHash, merchant, asset, amount, nonce
claimmerchanttoken
registerAgentownerdeviceHash, agent, asset, maxAmount, expiresAt?
revokeAgentownerdeviceHash
fundEscrowownerdeviceHash, token, amount
defundEscrowownerdeviceHash, token, amount
ts
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

ts
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 confirmed

Events

ts
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 days

Event types and the webhook relay are covered in Webhooks & events.