pinelabs-agent-toolkit
v0.1.2
Published
Pine Labs Agent Toolkit — Pine Labs payment APIs as tools for AI agent frameworks (OpenAI, LangChain, Vercel AI SDK, Anthropic Claude). Generated from the same OpenAPI spec that powers the Fern SDKs.
Readme
pinelabs-agent-toolkit
Pine Labs payment APIs as tools for AI agent frameworks — OpenAI (Agents SDK + Chat Completions), LangChain, Vercel AI SDK, and Anthropic Claude. Built on top of pinelabs-node.
74 Pine Labs operations (orders, refunds, payouts, payment links, settlements, subscriptions, …) become typed, schema-validated tools your agent can call.
Install
npm install pinelabs-agent-toolkitThen install only the framework adapter(s) you need (peer deps):
| Framework | Peer dependency |
| ----------------------- | -------------------------------- |
| OpenAI Agents SDK | @openai/agents |
| OpenAI Chat Completions | openai |
| LangChain | @langchain/core |
| Vercel AI SDK | ai |
| Anthropic Messages | @anthropic-ai/sdk |
| Claude Agent SDK | @anthropic-ai/claude-agent-sdk |
Requires Node.js ≥ 18.
Authenticate
The toolkit takes your Pine Labs OAuth credentials and handles token refresh automatically:
import { pinelabsEnvironment } from "pinelabs-agent-toolkit/shared";
const opts = {
environment: pinelabsEnvironment.UAT, // or pinelabsEnvironment.PROD
clientId: process.env.PINELABS_CLIENT_ID!,
clientSecret: process.env.PINELABS_CLIENT_SECRET!,
};Environments:
| Constant | Base URL |
| --------------------------- | ----------------------------------- |
| pinelabsEnvironment.UAT | https://pluraluat.v2.pinepg.in |
| pinelabsEnvironment.PROD | https://api.pluralpay.in |
Or pass any URL string directly to environment.
Quickstart by framework
OpenAI Agents SDK
Install a zod-3 compatible release:
npm i @openai/agents@^0.3. Newer majors require zod 4, which conflicts with this toolkit's zod-3 schemas.
import { Agent, run } from "@openai/agents";
import { PinelabsAgentToolkit, pinelabsEnvironment } from "pinelabs-agent-toolkit/openai";
const toolkit = new PinelabsAgentToolkit({
environment: pinelabsEnvironment.UAT,
clientId: process.env.PINELABS_CLIENT_ID!,
clientSecret: process.env.PINELABS_CLIENT_SECRET!,
});
const agent = new Agent({
name: "Payments Agent",
instructions: "Help the user manage Pine Labs payments.",
model: "gpt-4o",
tools: await toolkit.getAgentTools(),
});
const result = await run(agent, "Create a ₹500 order for ord-1");
console.log(result.finalOutput);OpenAI Chat Completions
The same /openai adapter also exposes Chat-Completions-shaped tools:
import OpenAI from "openai";
import { PinelabsAgentToolkit, pinelabsEnvironment } from "pinelabs-agent-toolkit/openai";
const toolkit = new PinelabsAgentToolkit({
environment: pinelabsEnvironment.UAT,
clientId: process.env.PINELABS_CLIENT_ID!,
clientSecret: process.env.PINELABS_CLIENT_SECRET!,
});
const openai = new OpenAI();
const messages: OpenAI.Chat.ChatCompletionMessageParam[] = [
{ role: "user", content: "Create a ₹500 order with reference ord-1" },
];
while (true) {
const r = await openai.chat.completions.create({
model: "gpt-4o",
messages,
tools: toolkit.getTools(),
});
const msg = r.choices[0].message;
messages.push(msg);
if (!msg.tool_calls?.length) break;
for (const call of msg.tool_calls) {
const out = await toolkit.handleToolCall(call.function.name, JSON.parse(call.function.arguments));
messages.push({ role: "tool", tool_call_id: call.id, content: out });
}
}LangChain
import { ChatOpenAI } from "@langchain/openai";
import { AgentExecutor, createOpenAIToolsAgent } from "langchain/agents";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { PinelabsAgentToolkit, pinelabsEnvironment } from "pinelabs-agent-toolkit/langchain";
const toolkit = new PinelabsAgentToolkit({
environment: pinelabsEnvironment.UAT,
clientId: process.env.PINELABS_CLIENT_ID!,
clientSecret: process.env.PINELABS_CLIENT_SECRET!,
});
const tools = toolkit.getTools();
const prompt = ChatPromptTemplate.fromMessages([
["system", "You manage Pine Labs payments."],
["human", "{input}"],
["placeholder", "{agent_scratchpad}"],
]);
const agent = await createOpenAIToolsAgent({ llm: new ChatOpenAI({ model: "gpt-4o" }), tools, prompt });
const executor = new AgentExecutor({ agent, tools });
const result = await executor.invoke({ input: "Create a ₹500 order ord-1" });
console.log(result.output);Vercel AI SDK
import { generateText } from "ai";
import { openai } from "@ai-sdk/openai";
import { PinelabsAgentToolkit, pinelabsEnvironment } from "pinelabs-agent-toolkit/ai-sdk";
const toolkit = new PinelabsAgentToolkit({
environment: pinelabsEnvironment.UAT,
clientId: process.env.PINELABS_CLIENT_ID!,
clientSecret: process.env.PINELABS_CLIENT_SECRET!,
});
const { text } = await generateText({
model: openai("gpt-4o"),
tools: toolkit.getTools(),
maxSteps: 5,
prompt: "Create a ₹500 order with reference ord-1",
});
console.log(text);Anthropic Messages API
import Anthropic from "@anthropic-ai/sdk";
import { PinelabsAgentToolkit, pinelabsEnvironment } from "pinelabs-agent-toolkit/anthropic";
const toolkit = new PinelabsAgentToolkit({
environment: pinelabsEnvironment.UAT,
clientId: process.env.PINELABS_CLIENT_ID!,
clientSecret: process.env.PINELABS_CLIENT_SECRET!,
});
const anthropic = new Anthropic();
const messages: Anthropic.MessageParam[] = [
{ role: "user", content: "Create a ₹500 order with reference ord-1" },
];
while (true) {
const r = await anthropic.messages.create({
model: "claude-3-5-sonnet-latest",
max_tokens: 1024,
tools: toolkit.getTools(),
messages,
});
messages.push({ role: "assistant", content: r.content });
const toolUses = r.content.filter((b): b is Anthropic.ToolUseBlock => b.type === "tool_use");
if (!toolUses.length) break;
const results = await Promise.all(
toolUses.map(async (tu) => ({
type: "tool_result" as const,
tool_use_id: tu.id,
content: await toolkit.handleToolCall(tu.name, tu.input),
})),
);
messages.push({ role: "user", content: results });
}Claude Agent SDK
The /anthropic adapter also exposes getAgentTools() for the Claude Agent SDK.
API surface
Each adapter exports PinelabsAgentToolkit and pinelabsEnvironment. Methods:
| Adapter | getTools() returns | getAgentTools() returns | handleToolCall() |
| ------------ | ---------------------------------------- | ------------------------------------------- | ------------------ |
| /openai | ChatCompletionTool[] (Chat Completions)| FunctionTool[] (Agents SDK) | ✓ |
| /langchain | DynamicStructuredTool[] | — | — |
| /ai-sdk | Record<name, Tool> | — | — |
| /anthropic | Anthropic.Tool[] (Messages API) | Anthropic.Tool[] (Claude Agent SDK shape) | ✓ |
| /shared | — | — | — |
The /shared subpath exports the underlying primitives (Pinelabs client, allToolDefinitions, pinelabsEnvironment) so you can build a custom adapter.
Customizing the tool set
Hooks live in src/overrides/tools.overrides.mjs (consumed at codegen time):
export const operationDenylist = ["deletePlan"]; // hide tools by operationId
export const nameOverrides = { createPaymentLink: "create_link" };
export const descriptionOverrides = {
createOrder: "Create a Pine Labs order. Amounts are in paise (₹1 = 100).",
};
export const parameterDescriptionOverrides = {
createOrder: { merchant_order_reference: "Your unique order id." },
};If you only need to filter at runtime without rebuilding, wrap the toolkit's output:
const tools = toolkit.getTools().filter((t) => !["delete_plan"].includes(t.name));Caveats
- Zod strict schemas. Tool parameter schemas are
z.object(...).strict()— agents that hallucinate extra fields will get a validation error. This is intentional; it surfaces the problem instead of silently dropping data. @openai/agents+ zod versions. The OpenAI Agents SDK is sensitive to its bundled Zod version. If you seeCannot read properties of undefined (reading 'type')fromzod/v3/types.js, pin a single Zod version in your project.- ESM-only
pinelabs-node. This package depends on the ESM-only Pine Labs SDK; consume it from an ESM project ("type": "module") or use dynamicimport(). getTools()results are JSON-stringified byhandleToolCallso you can feed them straight back into the model.
License
MIT
