Getting Started
Go from zero to your first API call in under 5 minutes.
Prerequisites
You need a 3PLGuys account with API access enabled. Contact your account manager or reach out via 3plguys.com/contact-us to get started.
What You'll Build
By the end of this guide, you'll have a working script that authenticates with the 3PLGuys API and retrieves your shipments. Here's the flow:
Step 1: Get Your Credentials
Once your developer application is approved, you'll receive:
| Credential | Description |
|---|---|
| Client ID | Public identifier for your app (e.g. myapp_abc123...) |
| Client Secret | Private key — keep this secure, never expose in client-side code |
| Allowed Scopes | Which API sections you can access (e.g. shipments, inventory) |
Security
Never commit your client secret to version control. Use environment variables or a secrets manager.
Step 2: Obtain an Access Token
Exchange your credentials for an access token using the OAuth 2.0 Authorization Code flow.
curl -X POST https://api.3plguys.com/oauth/token \-H "Content-Type: application/x-www-form-urlencoded" \-d 'grant_type=authorization_code&code=AUTH_CODE_FROM_REDIRECT&client_id=YOUR_CLIENT_ID&client_secret=YOUR_CLIENT_SECRET&redirect_uri=https%3A%2F%2Fyourapp.com%2Fcallback'
const res = await fetch("https://api.3plguys.com/oauth/token", {method: "POST",headers: { "Content-Type": "application/x-www-form-urlencoded" },body: new URLSearchParams({grant_type: "authorization_code",code: "AUTH_CODE_FROM_REDIRECT",client_id: process.env.CLIENT_ID,client_secret: process.env.CLIENT_SECRET,redirect_uri: "https://yourapp.com/callback",}),});const { access_token, refresh_token } = await res.json();
import httpxres = httpx.post("https://api.3plguys.com/oauth/token", data={"grant_type": "authorization_code","code": "AUTH_CODE_FROM_REDIRECT","client_id": os.environ["CLIENT_ID"],"client_secret": os.environ["CLIENT_SECRET"],"redirect_uri": "https://yourapp.com/callback",})data = res.json()access_token = data["access_token"]
{"access_token": "eyJhbGciOi...","token_type": "Bearer","expires_in": 3600,"refresh_token": "dGhpcyBpcyBh...","scope": "shipments inventory"}
The access_token is valid for 1 hour. Use the refresh_token to obtain new access tokens without re-authenticating.
Step 3: Make Your First API Call
Use your access token to fetch shipments:
curl https://api.3plguys.com/v0/shipments?take=5 \-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
const res = await fetch("https://api.3plguys.com/v0/shipments?take=5", {headers: { Authorization: `Bearer ${access_token}` },});const shipments = await res.json();console.log(`Found ${shipments.length} shipments`);
res = httpx.get("https://api.3plguys.com/v0/shipments",params={"take": 5},headers={"Authorization": f"Bearer {access_token}"},)shipments = res.json()print(f"Found {len(shipments)} shipments")
[{"id": "42","status": "pending","type": "outbound-pickpack","warehouse": {"id": "1","name": "Main Warehouse"},"notes": "","cartons": [{"id": "5","name": "24-Pack","quantity": 6,"contents": [{ "productId": "1", "sku": "ABC123", "productName": "Egg Shells", "quantity": 24 }]}],"totalCartonQuantity": 6,"totalProductQuantity": 144,"createdAt": "2025-01-15T10:30:00Z","updatedAt": "2025-01-15T10:30:00Z"}]
That's it — you're integrated!
Step 4: Explore the Sandbox
Before pointing at production, test your integration against the sandbox:
| Environment | Base URL |
|---|---|
| Production | https://api.3plguys.com |
| Sandbox | https://sandbox.3plguys.com |
The sandbox has completely separate data from production. Use your sandbox OAuth credentials to test without affecting real inventory or shipments.
curl https://sandbox.3plguys.com/v0/shipments \-H "Authorization: Bearer YOUR_SANDBOX_TOKEN"
Step 5: Handle Token Refresh
Access tokens expire after 1 hour. Here's how to refresh automatically:
async function refreshAccessToken(refreshToken) {const res = await fetch("https://api.3plguys.com/oauth/token", {method: "POST",headers: { "Content-Type": "application/x-www-form-urlencoded" },body: new URLSearchParams({grant_type: "refresh_token",refresh_token: refreshToken,client_id: process.env.CLIENT_ID,client_secret: process.env.CLIENT_SECRET,}),});const data = await res.json();// Important: store the NEW refresh token — it rotates each timereturn {accessToken: data.access_token,refreshToken: data.refresh_token,expiresIn: data.expires_in,};}
def refresh_access_token(refresh_token: str) -> dict:res = httpx.post("https://api.3plguys.com/oauth/token", data={"grant_type": "refresh_token","refresh_token": refresh_token,"client_id": os.environ["CLIENT_ID"],"client_secret": os.environ["CLIENT_SECRET"],})data = res.json()# Important: store the NEW refresh token — it rotates each timereturn {"access_token": data["access_token"],"refresh_token": data["refresh_token"],"expires_in": data["expires_in"],}
Refresh token rotation
Each token refresh returns a new refresh token. Always store and use the latest one. The previous refresh token is invalidated.
What's Next?
Automate Shipments
Create and manage SPD shipments end-to-end with the full draft → submit → track lifecycle.
Sync Inventory
Keep stock levels in sync across systems with polling and incremental sync patterns.
OAuth Deep Dive
Token refresh, scopes, security patterns, and building a production-ready auth wrapper.
More Guides
- Automating SPD Shipments — Ship full cartons to Amazon FBA and fulfillment centers
- Automating Pick & Pack — Fulfill customer orders with individual unit picking
- Connecting Shopify — Integrate Shopify for automated fulfillment
- Syncing Inventory — Keep stock levels accurate with polling and delta detection
- Building AI Integrations — Automate warehouse operations with MCP servers and AI agents