Cloudflare Agents run tool handlers on Workers and Durable Objects. Paybond guards tool execution at the same boundary — spend verify before side effects, auto-evidence after success. Paybond ships createPaybondCloudflareAgentsConfig on @paybond/kit/cloudflare-agents and @paybond/cloudflare-agents.
TypeScript only. Python Kit does not ship a Cloudflare Agents adapter. Use agent-agnostic spend controls or MCP agent spend controls for Python hosts.
Adapter reference: /docs/kit/cloudflare-agents.
spend verify on Workers
createPaybondCloudflareAgentsConfig wraps AI SDK tool 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 for Durable Object agents.
TypeScript native
Use @paybond/cloudflare-agents; Python hosts use agent-agnostic or MCP.
Why Paybond (not just Cloudflare Agents checks)?
Cloudflare Agents tool handlers do not enforce a spend limit, a per-operation permission check (capability token), or a signed completion receipt tied to a spend agreement (intent).
Model / input guardrails
- Cloudflare Agents alone
- Yes — SDK or host checks and approvals
- With Paybond
- Yes — plus Harbor authorize at the tool boundary
Spend boundary
- Cloudflare Agents alone
- No per-tool Harbor budget or capability token
- With Paybond
- Per-call and intent budgets enforced before invoke
Signed evidence
- Cloudflare Agents alone
- SDK traces / logs only
- With Paybond
- Signed completion digests bound to the intent
Intent binding
- Cloudflare Agents alone
- No Harbor intent or settlement receipt
- With Paybond
- Capability token + intentId from authenticated bind
Paid tool deny / HITL
- Cloudflare Agents alone
- Host or SDK approvals only
- With Paybond
- spend verify, deny, or HITL hold before side effects
| Capability | Cloudflare Agents alone | With Paybond |
|---|---|---|
| Model / input guardrails | Yes — SDK or host checks and approvals | Yes — plus Harbor authorize at the tool boundary |
| Spend boundary | No per-tool Harbor budget or capability token | Per-call and intent budgets enforced before invoke |
| Signed evidence | SDK traces / logs only | Signed completion digests bound to the intent |
| Intent binding | No Harbor intent or settlement receipt | Capability token + intentId from authenticated bind |
| Paid tool deny / HITL | Host or SDK approvals only | spend verify, deny, or HITL hold before side effects |
How it works
Adapter flow
getTools execute
Cloudflare Agent invokes a side-effecting tool
Paybond wrap
Harbor authorize before your handler runs
- Verify spend and operation
- Deny or HITL hold
- Issue / check capability
Tool runs
Your execute handler performs the paid work
Evidence
Wrapped execute finalizes spend + auto-evidence
Paybond wraps getTools AI SDK handlers: Harbor authorize before execute, then auto-evidence after success.
3-minute quickstart
Smoke the cloudflare-agents adapter sandbox contract — no Workers runtime required for this check:
terminal
paybond login
paybond agent demo cloudflare-agents smoke \
--operation paid-tool \
--requested-spend-cents 100 \
--evidence-preset cost_and_completion \
--format tableInstall the optional peers when running the native adapter in your app:
terminal
npm install @paybond/cloudflare-agents agents aiWhen the smoke succeeds you should see:
- ✓ Spend approved
- ✓ Tool completed
- ✓ Evidence verified (
cost_and_completion)
What success looks like
What success looks like
Authorized tool call · illustrative
- Operation
- paid-tool
- Status
- Approved
- Requested
- $1.00
- Evidence
- Verified
- Preset
- cost_and_completion
Scaffold
terminal
paybond init agent-middleware --framework cloudflare-agents --out paybond-cloudflare-agents.ts
paybond policy init --preset travel --out paybond.policy.yamlWire middleware
Recommended wiring
paybond.instrument with framework cloudflare-agents wraps AI SDK tool execute and returns toolApproval hooks.
paybond-session.ts
import { tool } from "ai";
import { z } from "zod";
import { Paybond } from "@paybond/kit";
const paybond = await Paybond.open({ apiKey: process.env.PAYBOND_API_KEY! });
const { tools, hooks } = await paybond.instrument({
policy: "travel",
framework: "cloudflare-agents",
tools: {
"travel.book_hotel": tool({
description: "Book a hotel room",
inputSchema: z.object({
city: z.string(),
estimatedPriceCents: z.number().int().nonnegative(),
}),
execute: async (args) => bookHotel(args),
}),
searchWeb: tool({
description: "Search the web",
inputSchema: z.object({ query: z.string() }),
execute: async (args) => searchWeb(args),
}),
},
});
// Return `tools` from getTools(); pass `hooks.toolApproval` to streamText/generateText.Already bound a run? createPaybondCloudflareAgentsConfig(run, tools) from @paybond/cloudflare-agents wraps execute without reloading policy.
Production: await instrumented.bind({ intentId, capabilityToken }) per session — see Agent middleware.
Production checklist
Production checklist
- Scaffold middleware with paybond init agent-middleware --framework cloudflare-agents
- Init a policy preset (e.g. travel) and validate tools
- Wire paybond.instrument({ framework: "cloudflare-agents", tools })
- Bind intentId and capabilityToken per session in production
- Smoke with paybond agent demo cloudflare-agents smoke before ship
Works with
Works with
- Cloudflare
- Vercel
- OpenAI
- MCP
Ready to test?
Related guides
- Agent-agnostic spend controls — fallback when Cloudflare Agents is not your primary stack
- Express and Fastify agent routes — HTTP servers wrapping
instrument() - MCP agent spend controls — stdio MCP for external hosts
Developer reference: /docs/kit/cloudflare-agents.