The OpenAI Responses API exposes function tools on a streaming response object — similar to Chat Completions tool calls, but with a different client surface. Paybond does not ship a dedicated Responses adapter; use the agent-agnostic path: wrap { name, execute } handlers and map Responses tool calls to Paybond envelopes at execute time.
Tool boundary, not model middleware
Paybond guards tool execution — not responses.create inference. Keep your OpenAI client for the model; intercept before your handler performs side effects.
Try it
terminal
paybond login
paybond agent demo generic smoke \
--operation paid-tool \
--requested-spend-cents 100 \
--evidence-preset cost_and_completion \
--format tablePolicy scaffold
terminal
paybond policy init --preset saas --out paybond.policy.yaml
paybond policy validate-tools --file paybond.policy.yaml --local-onlyWire handlers
Define side-effecting tools once; Paybond wraps them for authorization and evidence:
import OpenAI from "openai";
import { Paybond } from "@paybond/kit";
const openai = new OpenAI();
const paybond = await Paybond.open({ apiKey: process.env.PAYBOND_API_KEY! });
const { tools } = await paybond.instrument({
policy: "./paybond.policy.yaml",
tools: {
"saas.provision_seat": provisionSeat,
"saas.list_plans": listPlans,
},
});
const toolByName = new Map(tools.map((t) => [t.name, t]));
const response = await openai.responses.create({
model: "gpt-4.1",
tools: [
{
type: "function",
name: "saas.provision_seat",
description: "Provision a SaaS seat",
parameters: {
type: "object",
properties: {
planId: { type: "string" },
priceCents: { type: "integer" },
},
required: ["planId", "priceCents"],
},
},
],
input: "Provision a starter seat for acme-corp.",
});
// When the response includes a function_call output item:
for (const item of response.output) {
if (item.type === "function_call" && item.name === "saas.provision_seat") {
const wrapped = toolByName.get(item.name)!;
const args = JSON.parse(item.arguments);
const result = await wrapped.execute({
toolName: item.name,
toolCallId: item.call_id ?? item.id,
arguments: args,
});
// Feed result back into a follow-up responses.create call
}
}
Mapping rules
- Register every side-effecting function name in
paybond.policy.yamlwith matchingtools.*entries. - Use the Responses
call_id(or stable id) astoolCallIdin the Paybond envelope. - Read-only tools can omit Paybond wrapping or stay unregistered with
default_deny: falseonly when you accept the risk.
OpenAI Agents SDK vs Responses API
| Surface | Paybond path |
|---|---|
OpenAI Agents SDK (@openai/agents) | Native adapter — OpenAI Agents spend controls |
Responses API (openai.responses.create) | Agent-agnostic instrument() — this guide |
Choose the Agents SDK adapter when you use Runner.run and FunctionTool; use this guide when you integrate directly against Responses function tools.
Related guides
- Agent-agnostic spend controls — default
{ name, execute }wiring - OpenAI Agents SDK spend controls — native adapter
- Agent middleware — production bind
Developer reference: /docs/kit/agent-agnostic.