API Docs

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 CaseHow It Works
Intelligent order routingAI analyzes order data and picks the optimal warehouse based on proximity, stock, and cost
Inventory reorder alertsAgent 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 detectionSpot unusual order patterns, shipping delays, or inventory discrepancies
Automated fulfillmentOrders flow in, AI validates, creates PnP shipments, and tracks to completion
Operational reportsGenerate 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:

CategoryToolsWhat They Do
Inventory — Productslist_products, get_product, create_product, update_product, delete_product, restore_productFull CRUD on products, search by name or SKU
Inventory — Stockcheck_stock_levels, check_carton_stockCurrent unit counts per product or carton, with per-warehouse breakdown
Inventory — Cartonslist_carton_types, get_carton, create_carton, update_carton, delete_carton, restore_cartonManage carton types with dimensions, weight, and product contents
Warehouseslist_warehousesList all warehouses with addresses and details
Shipmentslist_shipments, get_shipmentList and inspect any shipment across all types
Pick & Packcreate_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_draftFull 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_attachmentFull SPD lifecycle including label and attachment management
Billing & Activitylist_invoices, get_invoice, list_notifications, list_recommendations, get_organizationInvoices, 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:

EndpointPurpose
https://mcp.3plguys.com/.well-known/oauth-protected-resourceProtected resource metadata (RFC 9728)
https://mcp.3plguys.com/.well-known/oauth-authorization-serverAuthorization server metadata (RFC 8414)
https://mcp.3plguys.com/oauth/registerDynamic client registration (RFC 7591)
https://mcp.3plguys.com/oauth/authorizeAuthorization endpoint
https://mcp.3plguys.com/oauth/tokenToken endpoint
https://mcp.3plguys.com/mcpMCP 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 at
123 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 loop
async 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 them
if (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 response
return response.content.find(c => c.type === "text")?.text;
}
}
}
// Example usage
const 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 situation
const 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 definitions
const 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_notes tools to tag AI-created shipments for tracking

Next Steps