Skip to content
Tenzro
← All tutorials
Tutorial · Payments

Agentic commerce workflows

Let an agent buy from merchants on your behalf: AP2 checkout and payment mandates, the ACP buyer side, layered spending ceilings, settlement over x402 or MPP, and an audit trail.

Advanced30 min

An agent that shops for you needs three things: a clear statement of what you allow it to buy, a way to take part in a merchant's checkout, and limits the network enforces no matter what the agent does. On Tenzro Network 1 these are AP2 mandates, the ACP buyer side and your agent's delegation scope. This tutorial walks one purchase from mandate to settlement and audit.

The flow

  1. You, the principal, sign a CheckoutMandate: what the agent may buy, from whom, up to how much, in which asset, on which chains, until when.
  2. The agent opens a checkout with an ACP merchant as the buyer and builds the cart.
  3. The agent signs a PaymentMandate for that exact cart, bound to your CheckoutMandate.
  4. The network validates the pair against every ceiling.
  5. The agent pays through the rail the merchant accepts, x402 or MPP, in TNZO or stablecoins.
  6. The validated pair is stored under your DID for audit.

Every payment passes these ceilings, outermost first:

CeilingSet byWhat it bounds
CheckoutMandateYou, per purchase intentTotal, asset, merchants, categories, chains, number of uses, expiry
Delegation scopeYou, per agent, in the consolePer-transaction and daily caps, allowed operations, protocols and chains
Escrow (optional)You, when the mandate pre-locks fundsThe amount actually available to release
Agent bond (optional)The agent's operatorWhat is slashed if the agent breaks a mandate

Prerequisites

1. Read the protocol profile

The node reports the AP2 version it speaks, the mandate kinds, the presence modes (human present or not present), the key-binding forms and the ceilings it applies.

ts
import { TenzroClient } from "tenzro-sdk";

const client = new TenzroClient({ endpoint: "https://rpc.tenzro.xyz" });
const info = await client.ap2().protocolInfo();
console.log(info.mandate_kinds, info.presence_modes, info.ceilings);

2. Sign the CheckoutMandate as the principal

The CheckoutMandate is your pre-authorisation. Amounts are in the smallest unit of the asset; for USDC, 6 decimals, so 25000000 is 25 USDC. Leave max_uses out for a single charge.

ts
const checkout = {
  mandate_id: "chk-2026-10-02-001",
  principal_did: "did:tenzro:human:<your-id>",
  agent_did: "did:tenzro:machine:<your-id>:<agent-id>",
  description: "Buy up to 25 USDC of labelled image data for the detector fine-tune",
  max_amount: 25000000,
  asset: "USDC",
  allowed_merchants: ["did:tenzro:machine:<merchant-id>"],
  allowed_categories: ["datasets"],
  accepted_chains: ["tenzro"],
  issued_at: "2026-10-02T09:00:00Z",
  expires_at: "2026-10-03T09:00:00Z",
  presence: "human_not_present",
};

// Signed by the principal's account; confirm with your passkey when prompted.
const checkoutVdc = await client.ap2().signMandate("checkout", checkout, checkout.principal_did);

The node builds the canonical AP2 preimage, signs it with the principal's account and returns a verifiable credential that verifies itself before it is returned. The caller never handles key material.

3. Build the cart as an ACP buyer

The merchant sells through the Agentic Commerce Protocol (ACP). The agent acts on the buyer side: it opens a checkout session with the merchant, adds items, and receives a priced cart with line items and a total. Tenzro maps the ACP cart onto a PaymentMandate one to one:

ACP checkoutPaymentMandate field
Line items (id, title, quantity, unit price, total)items (sku, description, quantity, unit_price, total, category)
Order total and currencytotal_amount, asset
Merchant identitymerchant_did
Checkout expiryexpires_at

Before committing, the agent checks the cart locally against the CheckoutMandate: same asset, a merchant on the list, a total under max_amount. The network checks again in step 5, so a buggy or manipulated agent cannot get past it.

4. Sign the PaymentMandate as the agent

The agent commits to the exact cart. checkout_mandate_id ties it to your mandate, and chain must be one of your accepted_chains.

ts
const payment = {
  mandate_id: "pay-2026-10-02-001",
  checkout_mandate_id: checkout.mandate_id,
  agent_did: checkout.agent_did,
  merchant_did: "did:tenzro:machine:<merchant-id>",
  items: [
    { sku: "img-set-street-v2", description: "Street scenes, 5k labelled images", quantity: 1, unit_price: 18000000, total: 18000000, category: "datasets" },
  ],
  total_amount: 18000000,
  asset: "USDC",
  chain: "tenzro",
  committed_at: "2026-10-02T09:14:00Z",
  expires_at: "2026-10-02T09:44:00Z",
};

// Run inside the agent runtime, authenticated as the agent.
const agentClient = new TenzroClient({ endpoint: "https://rpc.tenzro.xyz" });
const paymentVdc = await agentClient.ap2().signMandate("payment", payment, payment.agent_did);

5. Validate the pair

Validation checks that both credentials verify, that the payment references the checkout, that items, totals, asset, merchant and chain fit the checkout, and, with enforceDelegation set, that the total also fits the agent's delegation scope.

ts
const result = await client.ap2().validateMandatePair(checkoutVdc, paymentVdc, true);
if (!result.valid) throw new Error(result.error);

console.log(result);
// {
//   valid: true,
//   checkout_mandate_id: "chk-2026-10-02-001",
//   payment_mandate_id: "pay-2026-10-02-001",
//   principal_did: "did:tenzro:human:...",
//   agent_did: "did:tenzro:machine:...",
//   delegation_enforced: true
// }

A single mandate can be checked on its own with verifyMandate(vdc), which returns the mandate id, kind and signer.

6. Pay the merchant

Complete the ACP checkout with the payment rail the merchant accepts:

  • x402: the merchant's payment endpoint answers 402 Payment Required; the agent's SDK answers the challenge in USDC or TNZO and retries. See Payments with x402.
  • MPP: for merchants that meter a session, the agent opens an MPP session and settles when it closes. See Payments with MPP.
  • Escrow: if your CheckoutMandate carried an escrow_id, the funds were locked when you signed and the payment releases them to the merchant.

The same ceilings run again at settlement. A payment that would push the agent over its daily cap is refused even if the mandate pair was valid.

7. Audit what the agent bought

Validated pairs are stored under the principal's DID with the mandate ids, the DIDs involved, amounts, asset, chain, expiry, whether delegation was enforced, and the signed credentials themselves.

ts
const { mandates } = await client.ap2().listMandates("did:tenzro:human:<your-id>");
for (const m of mandates) {
  console.log(m.mandate_id, m.merchant_did, m.total_amount, "of", m.max_amount, m.asset);
}

If an agent ever pays outside a mandate, report it with tenzro_ap2ReportMandateViolation. When the agent carries an agent bond, a proven violation slashes it.

Next steps