Vercel AI SDK + Signbee: tool() for Markdown Signing from generateText
In modern Next.js applications, the Vercel AI SDK has become the undisputed runtime for managing agent loops, structured outputs, and tool calling. But while language models excel at synthesizing agreement terms and drafting bespoke contractual clauses, entering into an enforceable contract is an irreversible legal ceremony. Here is how builders wire Signbee into the Vercel AI SDK using the official tool() primitive, Zod schemas, generateText, and deliberate gating to dispatch legally binding e-signatures directly from autonomous workflows.
Founder, Signbee (B2bee Ltd)
SDK Primitive
/api/v1/send
Type-Safe Inputs
toolApproval
The Vercel AI SDK standardizes tool execution across OpenAI, Anthropic, Google, and open-source models within Next.js runtimes. By wrapping Signbee's zero-friction REST API into an AI SDK tool(), your agent can draft structured markdown agreements, validate counterparty parameters, and trigger legal ceremonies without heavy PDF libraries or bloated SDKs.
- Single primitive wiring: Define a
sendDocumenttool usingtool({ description, inputSchema, execute })from'ai'. Zod validates markdown, recipient_name, and recipient_email (and sender fields when no API key). - The irreversible execution boundary: Text generation and prompt loops are idempotent and reversible. Contract execution is legally binding under US ESIGN, EU eIDAS, and the UK Electronic Communications Act 2000. Gate signing with
toolApproval: { sendDocument: 'user-approval' }, then complete the two-call approval flow before execute runs. - Multi-step agent loops: Configure
generateTextorstreamTextwithstopWhen: isStepCount(5)to let the agent reconcile deal terms, inspect customer data, assemble the markdown contract, and dispatch the signing packet. - Zero template overhead: The tool's execute handler executes a single HTTP POST tohttps://signb.ee/api/v1/send, which returns
document_idandstatuswhile Signbee emails the signing URL to the recipient. - Composable agent architecture: Compare this clean pattern to our previous explorations ofOpenAI Function Callingand enterprise analytical handoffs in ourOpenAI Data Agent Signing Handoffguide.
Watch — Vercel AI SDK tool() + Signbee markdown signing — https://www.youtube.com/watch?v=Pgf4hN1yPdk
The Next.js Agent Dilemma: Reversible Thought vs Irreversible Action
When building AI agents in Next.js using the Vercel AI SDK, developers quickly fall in love with the composability of generateText and streamText. The AI SDK decouples your application code from underlying model providers like OpenAI, Anthropic, and Google, while providing first-class primitives for tool calling, structured object generation, and streaming UI components.
In a typical conversational agent, a user might instruct the system: “Prepare a standard 6-month consulting agreement for Acme Corp at $150 per hour with weekly milestones.” The language model accesses internal product databases, parses customer metadata, generates structured clauses, and presents a polished draft in CommonMark markdown.
This is where many agent implementations stumble into a perilous trap. Builders often conflate generating text with executing commitments. In software systems, reading data, drafting documents, and rewriting prose are reversible operations. If a model hallucinates a liability cap or misinterprets an hourly rate during drafting, the user simply adjusts the prompt or asks for a revision.
Digital signing is fundamentally different. E-signatures belong to a strict category of irreversible state mutations. Under statutory frameworks including the United States Electronic Signatures in Global and National Commerce (ESIGN) Act, the European Union eIDAS regulation, and the United Kingdom Electronic Communications Act 2000, a signed document is a legally binding commercial contract. Once executed, it creates legally enforceable liabilities, triggers financial obligations, and establishes immutable SHA-256 cryptographic audit certificates.
Therefore, the optimal architecture for agentic e-signatures in Next.js does not let the LLM blindly self-certify. Instead, we use the Vercel AI SDK to govern the reasoning loop, drafting terms into structured CommonMark markdown, and hand off execution to Signbee through a dedicated, strongly typed, and deliberately gated tool().
Defining the sendDocument Tool with tool() and Zod inputSchema
The core building block of tool calling in the Vercel AI SDK is the tool() helper exported directly from 'ai'. According to the official Vercel AI SDK specification, a tool is declared with three essential properties:
- description: A concise explanation that instructs the model when and why to invoke the tool.
- inputSchema: A Zod schema (or Standard Schema) defining the required arguments, field descriptions, and validation constraints.
- execute: An asynchronous function that receives the typed arguments and executes the external operation.
Notice how clean this interface is compared to legacy platforms. There are no proprietary multi-megabyte PDF libraries, no coordinate-based signature tag matrices, and no complex XML envelopes. The tool accepts pure markdown plus a single recipient, and fires one HTTP POST to Signbee's REST endpoint at https://signb.ee/api/v1/send.
Here is the production implementation of our sendDocument tool:
import { tool } from "ai";
import { z } from "zod";
// Matches live POST https://signb.ee/api/v1/send (single recipient)
const SendDocumentInputSchema = z.object({
title: z
.string()
.min(3)
.max(120)
.optional()
.describe("Optional document title; Signbee extracts one from markdown when omitted"),
markdown: z
.string()
.min(10)
.describe("Full legal agreement text in CommonMark markdown"),
recipient_name: z
.string()
.min(1)
.describe("Full legal name of the single recipient"),
recipient_email: z
.string()
.email()
.describe("Email address where Signbee sends the signing link"),
webhook_url: z
.string()
.url()
.optional()
.describe("Optional HTTPS webhook (Pro/Business) for document lifecycle events"),
expires_in_days: z
.number()
.int()
.positive()
.optional()
.describe("Optional signing window in days (default 7)"),
// Required only when calling without an API key (sender OTP path)
sender_name: z.string().min(1).optional(),
sender_email: z.string().email().optional(),
});
export const sendDocumentTool = tool({
description:
"Dispatch a markdown agreement for e-signature via Signbee. With an API key, returns document_id and status pending_recipient; the signing URL is emailed to the recipient (not returned in JSON).",
inputSchema: SendDocumentInputSchema,
execute: async (input) => {
const {
title,
markdown,
recipient_name,
recipient_email,
webhook_url,
expires_in_days,
sender_name,
sender_email,
} = input;
const hasApiKey = Boolean(process.env.SIGNBEE_API_KEY);
if (!hasApiKey && (!sender_name || !sender_email)) {
throw new Error(
"sender_name and sender_email are required when SIGNBEE_API_KEY is not set",
);
}
const response = await fetch("https://signb.ee/api/v1/send", {
method: "POST",
headers: {
"Content-Type": "application/json",
...(hasApiKey && {
Authorization: `Bearer ${process.env.SIGNBEE_API_KEY}`,
}),
},
body: JSON.stringify({
markdown,
recipient_name,
recipient_email,
...(title && { title }),
...(webhook_url && { webhook_url }),
...(expires_in_days && { expires_in_days }),
...(!hasApiKey && { sender_name, sender_email }),
}),
});
if (!response.ok) {
const errorText = await response.text();
throw new Error(`Signbee API dispatch failed (${response.status}): ${errorText}`);
}
const payload = await response.json();
// Authenticated path: document_id + status (e.g. pending_recipient). Signing URL is emailed.
return {
success: true,
document_id: payload.document_id,
status: payload.status,
message: `Agreement dispatched to ${recipient_name} <${recipient_email}>. Status: ${payload.status}.`,
};
},
});By utilizing inputSchema with Zod, TypeScript automatically infers the exact types for the execute argument object. If the LLM generates invalid JSON or missesrecipient_email, the Vercel AI SDK intercepts the error, returns structured validation feedback, and prompts the model to correct the parameters before network execution occurs.
Multi-Step Loops with generateText, streamText, and stopWhen
In real-world business automation, an agent rarely calls a signing tool in isolation on the very first step. A user might say:“Calculate our standard retainer terms for client TechCorp, formulate an NDA addendum, and send it over for signature.”
To handle multi-step agent interactions where tools are chained together, the Vercel AI SDK provides the stopWhen parameter inside generateText and streamText. When configured, the SDK runs an autonomous loop: the model generates a tool call, the tool executes, the result feeds back into the conversation context, and the model evaluates whether further reasoning is required.
To prevent accidental infinite loops and runaway token expenditure, the SDK provides built-in stopping conditions such asisStepCount(n) and hasToolCall(...). Here is how to wire multi-step signing inside a Next.js server route:
import { generateText, isStepCount, hasToolCall } from "ai";
import { openai } from "@ai-sdk/openai";
import { sendDocumentTool } from "@/lib/ai/tools/send-document";
export async function POST(req: Request) {
const { prompt } = await req.json();
const result = await generateText({
model: openai("gpt-4o"),
system: `You are an executive commercial operations assistant.
When asked to draft an agreement, assemble professional CommonMark markdown with clear clauses,
recitals, signature placeholders, and commercial terms. Once drafted and verified, use the
sendDocument tool to dispatch the agreement for legal electronic signature.`,
prompt,
tools: {
sendDocument: sendDocumentTool,
},
// Multi-step loop: continue execution up to 5 steps, or stop once the document tool has been executed
stopWhen: [isStepCount(5), hasToolCall("sendDocument")],
});
return Response.json({
text: result.text,
steps: result.steps.map((step) => ({
toolCalls: step.toolCalls.map((tc) => tc.toolName),
text: step.text,
})),
});
}When this route runs, the AI SDK manages the entire lifecycle. In Step 1, the model evaluates the prompt and generates the markdown document. In Step 2, it invokes sendDocument with markdown,recipient_name, and recipient_email. Signbee emails the signing URL to the recipient and returnsdocument_id plus status (for example pending_recipient) — not signing links in JSON. In Step 3, the model reviews that status payload and writes a concise confirmation for the operator.
The Irreversible Action Boundary: Gating E-Signatures with toolApproval
While multi-step autonomy is thrilling, deploying autonomous contract dispatching straight into production without guardrails violates enterprise risk governance. An LLM must never have unchecked authority to unilaterally execute contracts without human oversight.
The Vercel AI SDK addresses this critical safety requirement through its native toolApproval feature. Designed specifically for high-stakes operations such as moving capital, altering permissions, or executing legal instruments,toolApproval intercepts tool calls before the execute function runs.
By marking a sensitive tool with 'user-approval', the SDK does not pause the firstgenerateText call. It finishes and returns tool-approval-request parts inresult.content. Your UI (or Slack bot) shows the drafted markdown and recipient to an authorized operator. You append a tool-approval-response, then call generateText again so approved tools execute.
import {
generateText,
type ModelMessage,
type ToolApprovalResponse,
} from "ai";
import { openai } from "@ai-sdk/openai";
import { sendDocumentTool } from "@/lib/ai/tools/send-document";
export async function runGatedContractAgent(
userPrompt: string,
approve: (input: unknown) => Promise<boolean>,
) {
const messages: ModelMessage[] = [{ role: "user", content: userPrompt }];
// Call 1: generateText does NOT pause — it returns tool-approval-request parts
const pending = await generateText({
model: openai("gpt-4o"),
system: "You are an autonomous contract assistant. Draft comprehensive terms and request signature.",
messages,
tools: {
sendDocument: sendDocumentTool,
},
toolApproval: {
sendDocument: "user-approval",
},
});
messages.push(...pending.responseMessages);
const approvals: ToolApprovalResponse[] = [];
for (const part of pending.content) {
if (part.type === "tool-approval-request" && !part.isAutomatic) {
// Prefer toolCall.input (args is deprecated)
const input = part.toolCall.input;
const approved = await approve(input);
approvals.push({
type: "tool-approval-response",
approvalId: part.approvalId,
approved,
reason: approved ? "Operator confirmed markdown and recipient" : "Operator denied",
});
}
}
if (approvals.length === 0) {
return pending; // no gated tool call this turn
}
messages.push({ role: "tool", content: approvals });
// Call 2: approved tools execute; denials are returned to the model
return generateText({
model: openai("gpt-4o"),
messages,
tools: {
sendDocument: sendDocumentTool,
},
toolApproval: {
sendDocument: "user-approval",
},
});
}This architectural pattern provides the ideal synthesis of generative speed and enterprise compliance:
- Autonomous Drafting: The LLM handles 95% of the cognitive overhead—assembling clauses, structuring deliverables, formatting milestone dates, and rendering markdown tables.
- Human Verification: The authorized human executive inspects the rendered CommonMark preview, confirms the fee schedules and party identities, and hits “Approve”.
- Deterministic Execution: Signbee receives the verified markdown payload, converts it into an immutable PDF, records the tamper-evident SHA-256 hash, and initiates legal signing ceremonies.
This boundary ensures full statutory enforceability. If an audit ever questions the validity of a digital signature, your organization can demonstrate clear mutual intent, verified human review, and cryptographic non-repudiation.
Comparative Matrix: Agent Runtime Architecture
Depending on where your AI workloads run, you have multiple integration pathways. The table below compares implementing Signbee via the Vercel AI SDK against raw OpenAI function calling, desktop MCP servers, and legacy enterprise SDKs:
| Architectural Dimension | Vercel AI SDK tool() + Signbee | Raw OpenAI Function Calling | Claude Desktop MCP (signbee-mcp) | Legacy E-Sign SDKs (DocuSign, etc.) |
|---|---|---|---|---|
| Primary Runtime | Next.js App Router, Server Actions, Edge / Serverless | Direct Node.js / Python scripts calling OpenAI API | Local desktop MCP hosts (Claude Desktop, Cursor, Windsurf) | Heavy backend monoliths, enterprise servers |
| Document Format | Clean CommonMark markdown (natively generated by LLMs) | CommonMark markdown via JSON arguments | Markdown text or pre-compiled PDF binary | Pre-rendered PDF binaries, proprietary template IDs |
| Model Agnostic | Yes (OpenAI, Anthropic, Google, Mistral, Ollama) | No (Locked to OpenAI Chat Completions / Responses) | Depends on host client (primarily Claude) | Not applicable (Requires custom integration code) |
| Multi-Step Looping | Built-in (stopWhen: isStepCount(n)) | Manual loop logic and message history array updates | Managed by desktop client application | Complex multi-endpoint envelope orchestration |
| Execution Gating | Built-in (toolApproval: 'user-approval') | Manual custom conditional before calling API | Host prompt confirmation dialog | Admin dashboard configuration and role matrices |
| Bundle Impact | Minimal (standard fetch, zero heavy binaries) | Minimal (raw HTTP requests) | Zero (runs in external stdio child process) | Massive (bloated SDKs, native canvas/PDF deps) |
As the matrix illustrates, pairing the Vercel AI SDK with Signbee delivers the ultimate developer experience for Next.js applications: model neutrality, native type safety with Zod, built-in multi-step loops, and zero bundle bloat.
Full Production Example: Interactive Next.js Server Action
To see how this pattern fits into a complete Next.js 15 application, let us examine an interactive Server Action. In this scenario, an internal SaaS application allows sales representatives to prompt an agent to generate and dispatch a Master Services Agreement.
The Server Action leverages generateText, validates customer parameters, passes the sendDocumentTool, and returns the structured result directly to the React client:
"use server";
import { generateText, isStepCount } from "ai";
import { openai } from "@ai-sdk/openai";
import { sendDocumentTool } from "@/lib/ai/tools/send-document";
interface GenerateContractInput {
clientName: string;
clientEmail: string;
serviceScope: string;
monthlyRetainerUsd: number;
contractDurationMonths: number;
}
export async function createAndSendContract(input: GenerateContractInput) {
// Construct targeted prompt ensuring the model adheres to strict commercial guidelines
const prompt = `Draft a formal Master Services Agreement between 'Signbee Technologies Ltd' (Provider)
and '${input.clientName}' (Client, email: ${input.clientEmail}).
The agreement covers: ${input.serviceScope}.
Monthly Retainer Fee: $${input.monthlyRetainerUsd.toLocaleString()} USD.
Contract Duration: ${input.contractDurationMonths} months.
Include standard confidentiality clauses, IP assignment, 30-day termination notice, and governing law (Delaware).
Once the markdown is complete, execute the sendDocument tool to dispatch the agreement for signing.`;
try {
const { text, steps } = await generateText({
model: openai("gpt-4o"),
system: "You are a professional legal operations AI assistant. Always draft thorough, legally sound agreements.",
prompt,
tools: {
sendDocument: sendDocumentTool,
},
stopWhen: isStepCount(4),
});
// Extract tool execution output from steps
const executedStep = steps.find((s) => s.toolCalls.some((tc) => tc.toolName === "sendDocument"));
const toolResult = executedStep?.toolResults?.find((tr) => tr.toolName === "sendDocument");
return {
success: true,
summary: text,
dispatchMetadata: toolResult?.result || null,
};
} catch (error) {
console.error("Contract generation failed:", error);
return {
success: false,
error: error instanceof Error ? error.message : "Internal contract dispatch error",
};
}
}This Server Action runs cleanly in any serverless or Node.js runtime. Because Signbee does not require client-side PDF compilation or native canvas rendering, your Vercel deployment remains blazingly fast, with zero cold-start penalties from oversized package binaries.
Frequently Asked Questions About Vercel AI SDK and Signbee
How does the Vercel AI SDK tool() primitive integrate with Signbee?
The Vercel AI SDK tool() helper connects a Zod inputSchema to an async execute function. For Signbee, validate markdown, recipient_name, and recipient_email (plus sender_name/sender_email when not using an API key). execute POSTs to https://signb.ee/api/v1/send. With an API key, Signbee compiles markdown to PDF, emails the signing URL to the recipient, and returns document_id plus status (for example pending_recipient). Signing links are not returned in the JSON body.
Why should developers gate document signing tools with toolApproval or human verification?
Digital contracts are legally binding instruments governed by statutory frameworks including the US ESIGN Act, EU eIDAS regulation, and the UK Electronic Communications Act 2000. Unlike database querying or drafting prose, which are idempotent and easily reversible, dispatching an agreement creates enforceable liabilities, financial commitments, and immutable audit trails. Configure toolApproval with user-approval so the first generateText returns tool-approval-request parts; after a human tool-approval-response, a second generateText runs execute if approved. That two-call gate prevents hallucinated clauses and unauthorized dispatch while the model still drafts terms autonomously.
How do generateText, streamText, and stopWhen manage multi-step contract negotiation?
In complex agentic architectures, an AI agent often needs to perform multiple intermediate operations before executing an agreement—such as looking up client billing history, calculating tiered discount rates, assembling structured contract clauses, and requesting counterparty verification. Using generateText or streamText equipped with the stopWhen parameter and conditions like isStepCount(5) or hasToolCall('sendDocument'), the Vercel AI SDK orchestrates this multi-step loop automatically. When the model invokes a tool, the SDK executes it, feeds the output back into the message history, and triggers the next reasoning step. The loop continues iteratively until the stopping condition is satisfied, after which the model generates a final natural-language confirmation summarizing the agreement.
What makes Signbee's markdown API better suited for AI SDK agents than legacy PDF SDKs?
Legacy e-signature SDKs were built for traditional enterprise portals, requiring multi-megabyte client packages, coordinate-based signature tab placement, complex OAuth credential lifecycles, and manual PDF envelope assembly. These heavy dependencies bloat Next.js serverless functions and cause cold-start latency spikes. In contrast, Signbee is engineered specifically for autonomous AI agents and modern web runtimes. Modern LLMs naturally generate structured CommonMark markdown with headings, lists, and tables. Signbee accepts raw markdown via a single standard HTTP POST call, rendering crisp typography, managing signature canvases, and attaching SHA-256 cryptographic audit certificates automatically. This enables developers to implement production-grade contract signing in under fifty lines of TypeScript with zero bundle overhead.
The Builder's Perspective: Why Markdown Tools Beat Bloated SDKs
When we set out to build Signbee, our driving conviction was that software developers should never be forced to wrestle with 400-page API manuals or multi-megabyte SDK wrappers just to obtain a legally binding signature on a document. For twenty years, incumbent e-signature vendors designed their developer tools as an afterthought—clumsy layers glued on top of legacy graphical drag-and-drop dashboard engines.
The emergence of autonomous AI agents has laid bare the bankruptcy of that legacy paradigm. Modern agents do not click around in visual builders, coordinate pixel coordinates, or manage multi-token OAuth refresh workflows. Agents reason in tokens, generate structured CommonMark text, and interact with external systems through concise, deterministic HTTP tool calls.
The Vercel AI SDK is arguably the cleanest abstraction ever created for wiring LLM intelligence into real-world software. By pairing its native tool() helper with Signbee's markdown signing endpoint, you give your agent the power to execute real-world agreements in seconds—without sacrificing type safety, legal compliance, or serverless performance.
Whether you are building autonomous sales pipelines, automated client onboarding workflows, or internal operations bots, the integration is as simple as it gets: write your Zod schema, define your execute function, and let the agent run.
To explore other ways to integrate Signbee into your agentic stack, check out our developer guides on One API Call: Markdown to Signed PDF for AI Agents, wire OpenAI models using OpenAI Function Calling + Signbee, or learn how enterprise pipelines separate analysis from execution in our OpenAI Data Agent Signing Handoff guide. You can make your first contract dispatch call right now via https://signb.ee/api/v1/send. The agentic loop is complete; now go build.