Building AI-Powered Integrations
The 3PLGuys API is designed for machine consumption — structured REST endpoints, predictable responses, and a complete OpenAPI spec make it ideal for AI agents and automation tools. This guide covers the official 3PLGuys MCP server, AI-powered fulfillment agents, and intelligent automation pipelines.
Why AI + 3PLGuys?
AI agents can monitor inventory levels, automatically create shipments when thresholds are hit, answer natural-language questions about warehouse status, and make operational decisions faster than manual workflows.
What You Can Automate with AI
| Use Case | How It Works |
|---|---|
| Intelligent order routing | AI analyzes order data and picks the optimal warehouse based on proximity, stock, and cost |
| Inventory reorder alerts | Agent monitors stock levels and triggers purchase orders when thresholds are hit |
| Natural language warehouse queries | "How many units of SKU ABC123 are in stock?" → API call → formatted answer |
| Anomaly detection | Spot unusual order patterns, shipping delays, or inventory discrepancies |
| Automated fulfillment | Orders flow in, AI validates, creates PnP shipments, and tracks to completion |
| Operational reports | Generate daily summaries of shipments, inventory changes, and fulfillment metrics |
The 3PLGuys MCP Server
3PLGuys provides an official Model Context Protocol (MCP) server at https://mcp.3plguys.com. It uses Streamable HTTP transport with OAuth 2.0 authentication (including dynamic client registration), so any MCP-compatible AI assistant — Claude Desktop, Cursor, Windsurf, and others — can connect directly to your warehouse.
Available Tools
The MCP server exposes 46 tools across six categories:
| Category | Tools | What They Do |
|---|---|---|
| Inventory — Products | list_products, get_product, create_product, update_product, delete_product, restore_product | Full CRUD on products, search by name or SKU |
| Inventory — Stock | check_stock_levels, check_carton_stock | Current unit counts per product or carton, with per-warehouse breakdown |
| Inventory — Cartons | list_carton_types, get_carton, create_carton, update_carton, delete_carton, restore_carton | Manage carton types with dimensions, weight, and product contents |
| Warehouses | list_warehouses | List all warehouses with addresses and details |
| Shipments | list_shipments, get_shipment | List and inspect any shipment across all types |
| Pick & Pack | create_pnp_draft, set_pnp_shipping_address, get_pnp_shipping_address, set_pnp_items, get_pnp_items, set_pnp_notes, get_pnp_notes, submit_pnp, cancel_pnp, delete_pnp_draft | Full PnP lifecycle: create draft, set address/items/notes, submit, cancel |
| SPD (Small Parcel Delivery) | create_spd_draft, set_spd_items, get_spd_items, set_spd_notes, get_spd_notes, submit_spd, cancel_spd, delete_spd_draft, upload_spd_shipping_label, remove_spd_shipping_label, upload_spd_fnsku_label, remove_spd_fnsku_label, upload_spd_attachment, remove_spd_attachment | Full SPD lifecycle including label and attachment management |
| Billing & Activity | list_invoices, get_invoice, list_notifications, list_recommendations, get_organization | Invoices, notifications, AI-powered recommendations, and account info |
Connecting with Claude Desktop
Add the MCP server to your Claude Desktop configuration. OAuth is handled automatically — Claude will open a browser for you to log in on the first connection:
{"mcpServers": {"3plguys": {"type": "url","url": "https://mcp.3plguys.com/mcp"}}}
That's it. No API keys to manage, no local server to run. Claude discovers the OAuth endpoints via RFC 9728 metadata at /.well-known/oauth-protected-resource and handles the authorization code flow with PKCE automatically.
Connecting with Other MCP Clients
Any MCP client that supports Streamable HTTP + OAuth can connect. The server publishes standard discovery metadata:
| Endpoint | Purpose |
|---|---|
https://mcp.3plguys.com/.well-known/oauth-protected-resource | Protected resource metadata (RFC 9728) |
https://mcp.3plguys.com/.well-known/oauth-authorization-server | Authorization server metadata (RFC 8414) |
https://mcp.3plguys.com/oauth/register | Dynamic client registration (RFC 7591) |
https://mcp.3plguys.com/oauth/authorize | Authorization endpoint |
https://mcp.3plguys.com/oauth/token | Token endpoint |
https://mcp.3plguys.com/mcp | MCP Streamable HTTP endpoint (POST) |
The OAuth flow supports authorization_code and refresh_token grant types with PKCE (S256). The token endpoint auth method is none (public clients).
Example: AI Creates a Pick & Pack Shipment
With the MCP server connected, an AI assistant can fulfill a customer order through natural conversation. Behind the scenes, it calls separate tools for each step:
User: "Ship 5 units of product p_abc123 to Jane Doe at123 Main St, Austin TX 78701"AI calls: create_pnp_draft({ warehouseId: "w_1" })→ returns { id: "draft_xyz" }AI calls: set_pnp_shipping_address({draftId: "draft_xyz",name: "Jane Doe",address1: "123 Main St",city: "Austin",state: "TX",zip: "78701"})AI calls: set_pnp_items({draftId: "draft_xyz",items: [{ productId: "p_abc123", quantity: 5 }]})AI calls: submit_pnp({ draftId: "draft_xyz" })→ returns { id: "shp_final", status: "pending" }AI: "Done! Shipment shp_final is now pending fulfillment."
AI Agent with Function Calling
Build an autonomous agent using any LLM with function calling (Claude, GPT-4, etc.) to handle warehouse operations:
import Anthropic from "@anthropic-ai/sdk";const client = new Anthropic();const TPL_BASE = "https://api.3plguys.com/v0";const auth = { Authorization: `Bearer ${process.env.TPLGUYS_TOKEN}` };const tools = [{name: "check_stock_levels",description: "Get current stock levels for all products with per-warehouse breakdown",input_schema: {type: "object",properties: {updatedSince: { type: "string", description: "ISO 8601 timestamp" },take: { type: "number", default: 50 },skip: { type: "number", default: 0 },},},},{name: "list_shipments",description: "List shipments filtered by type and status",input_schema: {type: "object",properties: {type: { type: "string", enum: ["outbound-pickpack", "outbound-spd", "inbound-container", "inbound-spd"] },status: { type: "string", enum: ["draft", "pending", "processing", "forwarded", "cancelled"] },take: { type: "number", default: 50 },skip: { type: "number", default: 0 },},},},{name: "create_pnp_draft",description: "Create a Pick & Pack shipment draft",input_schema: {type: "object",properties: {warehouseId: { type: "string" },},required: ["warehouseId"],},},{name: "set_pnp_shipping_address",description: "Set the shipping address on a PnP draft",input_schema: {type: "object",properties: {draftId: { type: "string" },name: { type: "string" },address1: { type: "string" },city: { type: "string" },state: { type: "string" },zip: { type: "string" },},required: ["draftId", "name", "address1", "city", "state", "zip"],},},{name: "set_pnp_items",description: "Set items on a PnP draft",input_schema: {type: "object",properties: {draftId: { type: "string" },items: {type: "array",items: {type: "object",properties: {productId: { type: "string" },quantity: { type: "number" },},required: ["productId", "quantity"],},},},required: ["draftId", "items"],},},{name: "submit_pnp",description: "Submit a PnP draft for fulfillment",input_schema: {type: "object",properties: {draftId: { type: "string" },},required: ["draftId"],},},];async function handleTool(name, input) {switch (name) {case "check_stock_levels": {const params = new URLSearchParams({take: String(input.take || 50),skip: String(input.skip || 0),});if (input.updatedSince) params.set("updatedSince", input.updatedSince);return fetch(`${TPL_BASE}/inventory/products/breakdown?${params}`, {headers: auth,}).then(r => r.json());}case "list_shipments": {const params = new URLSearchParams({take: String(input.take || 50),skip: String(input.skip || 0),});if (input.type) params.set("type", input.type);if (input.status) params.set("status", input.status);return fetch(`${TPL_BASE}/shipments?${params}`, {headers: auth,}).then(r => r.json());}case "create_pnp_draft":return fetch(`${TPL_BASE}/shipments/pnp`, {method: "POST",headers: { ...auth, "Content-Type": "application/json" },body: JSON.stringify({ warehouseId: input.warehouseId }),}).then(r => r.json());case "set_pnp_shipping_address": {const { draftId, ...address } = input;return fetch(`${TPL_BASE}/shipments/pnp/${draftId}/shipping-address`, {method: "PUT",headers: { ...auth, "Content-Type": "application/json" },body: JSON.stringify(address),}).then(r => r.json());}case "set_pnp_items":return fetch(`${TPL_BASE}/shipments/pnp/${input.draftId}/items`, {method: "PUT",headers: { ...auth, "Content-Type": "application/json" },body: JSON.stringify({ items: input.items }),}).then(r => r.json());case "submit_pnp":return fetch(`${TPL_BASE}/shipments/pnp/${input.draftId}/submit`, {method: "POST",headers: auth,}).then(r => r.json());}}// Run the agent loopasync function runAgent(userMessage) {const messages = [{ role: "user", content: userMessage }];while (true) {const response = await client.messages.create({model: "claude-sonnet-4-20250514",max_tokens: 4096,tools,messages,system: "You are a warehouse operations assistant for 3PLGuys. Help manage inventory, shipments, and fulfillment.",});// If the model wants to use tools, execute themif (response.stop_reason === "tool_use") {const toolUse = response.content.find(c => c.type === "tool_use");const result = await handleTool(toolUse.name, toolUse.input);messages.push({ role: "assistant", content: response.content });messages.push({role: "user",content: [{type: "tool_result",tool_use_id: toolUse.id,content: JSON.stringify(result),}],});} else {// Final text responsereturn response.content.find(c => c.type === "text")?.text;}}}// Example usageconst answer = await runAgent("Check our inventory levels and tell me which products are running low");console.log(answer);
Automated Inventory Alerts
Use AI to generate intelligent alerts instead of simple threshold checks:
async function smartInventoryCheck() {const levels = await fetch(`${TPL_BASE}/inventory/products/breakdown?take=50`,{ headers: auth }).then(r => r.json());const shipments = await fetch(`${TPL_BASE}/shipments?type=outbound-pickpack&status=pending&take=50`,{ headers: auth }).then(r => r.json());// Ask AI to analyze the situationconst analysis = await runAgent(`Here's our current inventory:\n${JSON.stringify(levels)}\n\n` +`And pending outbound orders:\n${JSON.stringify(shipments)}\n\n` +`Identify any products at risk of stockout considering pending orders. ` +`Flag anything that needs immediate attention.`);if (analysis.includes("immediate attention") || analysis.includes("stockout")) {await sendSlackAlert(analysis);}}
Using the OpenAPI Spec
The 3PLGuys OpenAPI specification enables AI tools to understand the full API surface automatically:
curl https://api.3plguys.com/openapi.json -o openapi.json
Use it to:
- Generate typed clients in any language with
openapi-generator - Feed to AI agents so they understand every endpoint, parameter, and response schema
- Auto-generate MCP tools from the spec instead of writing them manually
- Validate requests before sending them to the API
import { parse } from "yaml";import fs from "fs";const spec = JSON.parse(fs.readFileSync("openapi.json", "utf-8"));// Extract endpoints as tool definitionsconst tools = Object.entries(spec.paths).flatMap(([path, methods]) =>Object.entries(methods).map(([method, details]) => ({name: `${method}_${path.replace(/\//g, "_").replace(/[{}:]/g, "")}`,description: details.summary || details.description,method: method.toUpperCase(),path,parameters: details.parameters || [],})));console.log(`Generated ${tools.length} tools from OpenAPI spec`);
AI-Discoverable Documentation
This developer portal includes an llms.txt file at the root that helps AI tools discover and understand the API:
curl https://developer.3plguys.com/llms.txt
The file provides a structured overview of all endpoints, key concepts, and documentation links — optimized for LLM consumption. AI coding assistants and automation tools can use this to quickly understand the API surface without reading every documentation page.
Best practices for AI integrations
- Always use the sandbox environment (
https://sandbox.3plguys.com) when developing and testing AI agents - Implement human-in-the-loop confirmation for destructive actions like submitting shipments
- Rate limit your AI agent's API calls — the sandbox allows 1,000 requests/hour
- Log all AI-initiated API calls for auditing and debugging
- Use the
set_pnp_notes/set_spd_notestools to tag AI-created shipments for tracking
Next Steps
- OAuth Integration Deep Dive — Secure token management for AI agents
- Automating Pick & Pack — The API lifecycle your AI agent will automate
- Syncing Inventory — Feed real-time stock data to AI monitoring
- Multi-Channel Fulfillment — AI-powered routing across sales channels