postbridge-langchain
v0.1.0
Published
PostBridge postal tools for LangChain JS and LangGraph — send physical letters to 5 countries from any LangChain agent.
Maintainers
Readme
postbridge-langchain (JS / TypeScript)
Drop-in PostBridge postal tools for LangChain JS and LangGraph — send physical letters to US, France, UK, Canada, and Germany from any LangChain Node/TypeScript agent.
Python user? Check the Python package:
pip install postbridge-langchain.
Install
npm install postbridge-langchain @langchain/core
# or
pnpm add postbridge-langchain @langchain/core
# or
yarn add postbridge-langchain @langchain/core@langchain/core is a peer dependency — bring your own version.
Quickstart — direct bindTools
import { ChatOpenAI } from "@langchain/openai";
import { postbridgeTools } from "postbridge-langchain";
const llm = new ChatOpenAI({ model: "gpt-4o-mini" });
const llmWithTools = llm.bindTools(postbridgeTools());
const response = await llmWithTools.invoke(
"Send a letter to Marie Dupont at 15 Rue de Rivoli, 75001 Paris, France."
);Quickstart — LangGraph createReactAgent
import { ChatOpenAI } from "@langchain/openai";
import { createReactAgent } from "@langchain/langgraph/prebuilt";
import { postbridgeTools } from "postbridge-langchain";
const agent = createReactAgent({
llm: new ChatOpenAI({ model: "gpt-4o-mini" }),
tools: postbridgeTools(),
});
const result = await agent.invoke({
messages: [{ role: "user", content: "Send a letter to Paris..." }],
});Quickstart — AgentExecutor
import { ChatOpenAI } from "@langchain/openai";
import { AgentExecutor, createToolCallingAgent } from "langchain/agents";
import { ChatPromptTemplate } from "@langchain/core/prompts";
import { postbridgeTools } from "postbridge-langchain";
const tools = postbridgeTools();
const prompt = ChatPromptTemplate.fromMessages([
["system", "You are a postal assistant. Use the tools to send letters."],
["human", "{input}"],
["placeholder", "{agent_scratchpad}"],
]);
const agent = await createToolCallingAgent({
llm: new ChatOpenAI({ model: "gpt-4o-mini" }),
tools,
prompt,
});
const executor = new AgentExecutor({ agent, tools });
const result = await executor.invoke({ input: "Send a letter to Paris..." });Tools available
| Tool | HTTP | Purpose |
|------|------|---------|
| list_services | GET /api/services/{country} | Discover services per country |
| quote_letter | POST /api/quote | Price a letter |
| send_letter | POST /api/send | Mail it |
| track_letter | GET /api/track/{letter_id} | Live status |
| get_proof | GET /api/proof/{letter_id} | Signed PostalProof VC |
| get_balance | GET /api/balance | Wallet + ledger |
| negotiate_pricing | POST /api/anp/offer | ANP tiered offer |
| accept_offer | POST /api/anp/accept | Lock in tier |
Subset selection
Filter to the tools your agent actually needs:
// Read-only reporter
const tools = postbridgeTools({
only: ["list_services", "quote_letter", "track_letter", "get_proof"],
});
// Send-only dispatcher
const tools = postbridgeTools({ only: ["send_letter", "track_letter"] });
// Full negotiation flow
const tools = postbridgeTools({
only: ["negotiate_pricing", "accept_offer", "send_letter"],
});Authentication
Tools call https://api.postbridge.ai. By default the dispatcher reads POSTBRIDGE_API_KEY from process.env:
export POSTBRIDGE_API_KEY=pb_live_...
node your-agent.mjsOr pass a token explicitly when building the toolkit:
const tools = postbridgeTools({ apiKey: "pb_live_..." });Get a key in one request
curl -X POST https://api.postbridge.ai/auth/agent \
-H 'Content-Type: application/json' \
-d '{"agent_id": "my-agent", "agent_name": "My LangChain Agent"}'Returns a scoped pb_live_... key. Or skip the key entirely and use x402 USDC per-request.
Direct dispatcher usage (outside an agent loop)
import { execute } from "postbridge-langchain";
const quote = await execute("quote_letter", {
to_name: "Marie Dupont",
to_line1: "15 Rue de Rivoli",
to_city: "Paris",
to_postal_code: "75001",
to_country: "FR",
service: "fr_lettre_verte",
});
console.log(quote);How it works
- Single source of truth — the canonical tool catalog (
tools.json) is bundled into the package. The same catalog powers the Pythonpostbridge-corepackage, so every agent framework across Python and JS sees identical tool definitions, identical Zod/Pydantic validation, and identical HTTP mappings. - Zod schemas, auto-generated — each tool's JSON Schema is converted to a Zod object at runtime so LangChain's tool-calling prompts include proper arg types, enums, and descriptions.
- Server-side determinism — the tools never compute prices or format addresses. All of that happens in the PostBridge API, which enforces rate-table pricing, country-specific address formatting, and recipient-country postal routing.
- Margin confidentiality — internal pricing fields are stripped from every response before reaching the client.
TypeScript support
Full .d.ts types shipped. Import the types if you're writing wrapping code:
import type {
Catalog,
ToolDef,
DispatchResult,
PostBridgeToolsOptions,
} from "postbridge-langchain";Related packages
Python:
postbridge-core— raw catalog + dispatcherpostbridge-crewai— CrewAI toolspostbridge-langchain— LangChain (Python) toolspostbridge-llamaindex— LlamaIndex tools
Docs:
- postbridge.ai — landing
- postbridge.ai/developers.html — full API reference
- postbridge.ai/.well-known/agent.json — agent metadata
License
Proprietary. See postbridge.ai.
