paybondpaybond
Sign in

Recipe · Framework

Spend controls for Mastra createTool handlers

spend verify before createTool execute, auto-evidence after success, and policy budgets for Mastra — TypeScript.

  1. 1Wire
  2. 2Authorize
  3. 3Smoke

You'll build

Mastra workflows with spend verify on paid steps

Mastra agents expose tools via createTool({ execute }). Paybond ships createPaybondMastraConfig on @paybond/kit/mastra and @paybond/mastra. spend verify runs before side-effecting tools execute; auto-evidence fires after success.

TypeScript only. Python Kit does not ship a Mastra adapter. Use agent-agnostic spend controls or MCP agent spend controls for Python hosts.

Adapter reference: /docs/kit/mastra.

  • spend verify before execute

    createPaybondMastraConfig wraps createTool execute on side-effecting tools.

  • Auto-evidence

    Wrapped execute finalizes spend and submits signed evidence after success.

  • Policy budgets

    Versioned YAML caps per-call and intent spend — default-deny for paid tools.

  • TypeScript native

    Use @paybond/mastra or @paybond/kit/mastra; Python hosts use agent-agnostic or MCP.

Why Paybond (not just Mastra checks)?

Mastra tool wrappers do not enforce a spend limit, a per-operation permission check (capability token), or a signed completion receipt tied to a spend agreement (intent).

Mastra alone versus Paybond Harbor spend controls
  • Model / input guardrails

    Mastra alone
    Yes — SDK or host checks and approvals
    With Paybond
    Yes — plus Harbor authorize at the tool boundary
  • Spend boundary

    Mastra alone
    No per-tool Harbor budget or capability token
    With Paybond
    Per-call and intent budgets enforced before invoke
  • Signed evidence

    Mastra alone
    SDK traces / logs only
    With Paybond
    Signed completion digests bound to the intent
  • Intent binding

    Mastra alone
    No Harbor intent or settlement receipt
    With Paybond
    Capability token + intentId from authenticated bind
  • Paid tool deny / HITL

    Mastra alone
    Host or SDK approvals only
    With Paybond
    spend verify, deny, or HITL hold before side effects

How it works

Paybond wraps Mastra createTool execute: Harbor authorize before the tool runs, then auto-evidence after success.

Adapter flow

  1. createTool execute

    Mastra agent invokes a side-effecting tool

  2. Paybond wrap

    Harbor authorize before your handler runs

    • Verify spend and operation
    • Deny or HITL hold
    • Issue / check capability
  3. Tool runs

    Your execute handler performs the paid work

  4. Evidence

    Wrapped execute finalizes spend + auto-evidence

Paybond wraps Mastra createTool execute: Harbor authorize before the tool runs, then auto-evidence after success.

3-minute quickstart

Smoke the mastra adapter sandbox contract — no Mastra runtime required for this check:

Terminal
Terminal commandSwipe to inspect long lines
paybond login
paybond agent demo mastra smoke \
  --operation paid-tool \
  --requested-spend-cents 100 \
  --evidence-preset cost_and_completion \
  --format table

Install the optional peer when running the native adapter in your app:

Terminal
Terminal commandSwipe to inspect long lines
npm install @paybond/mastra @mastra/core

When the smoke succeeds you should see:

  • ✓ Spend approved
  • ✓ Tool completed
  • ✓ Evidence verified (cost_and_completion)

What success looks like

Example status after a Paybond-guarded Mastra tool call: approved spend, requested amount, and verified cost_and_completion evidence.

What success looks like

Authorized tool call · illustrative

Sandbox path
Operation
paid-tool
Status
Approved
Requested
$1.00
Evidence
Verified
Preset
cost_and_completion

Scaffold

Terminal
Terminal commandSwipe to inspect long lines
paybond init agent-middleware --framework mastra --out paybond-mastra.ts
paybond init --template mastra-travel-agent --framework mastra
paybond policy init --preset travel --out paybond.policy.yaml

Wire middleware

Recommended wiring

paybond.instrument with framework mastra wraps createTool execute on side-effecting tools.

paybond-session.ts

TS
TypeScript code sampleSwipe to inspect long lines
import { createTool } from "@mastra/core/tools";
import { z } from "zod";
import { Paybond } from "@paybond/kit";

const paybond = await Paybond.open({ apiKey: process.env.PAYBOND_API_KEY! });

const { tools } = await paybond.instrument({
  policy: "travel",
  framework: "mastra",
  tools: [
    createTool({
      id: "travel.book_hotel",
      description: "Book a hotel room",
      inputSchema: z.object({
        city: z.string(),
        estimatedPriceCents: z.number().int().nonnegative(),
      }),
      execute: async (args) => bookHotel(args),
    }),
    createTool({
      id: "search.web",
      description: "Search the web",
      inputSchema: z.object({ query: z.string() }),
      execute: async (args) => searchWeb(args),
    }),
  ],
});

// Register `tools` with your Mastra agent.

Already bound a run? createPaybondMastraConfig(run, tools) from @paybond/mastra wraps execute without reloading policy.

Production: await instrumented.bind({ intentId, capabilityToken }) per session — see Agent middleware.

Production checklist

Production checklist for Paybond-guarded Mastra tools.

Production checklist

Works with

Works with

  • Mastra
  • Vercel
  • OpenAI
  • MCP

Ready to test?

Developer reference: /docs/kit/mastra.