API Docs

Cartons

scope: inventory

Create and manage carton definitions. A carton describes a box configuration — its contents (which products and how many), physical dimensions, and weight. Contents, dimensions, and weight are set at creation and cannot be changed afterwards. Only the carton name can be updated.

Where cartons fit in

ProductCarton(contains N units of a product)stored in Warehouseshipped via SPD

Cartons are the physical packaging unit. Each carton type defines a box containing a set quantity of one product, with specific dimensions and weight.

Endpoints

GET
/v0/inventory/cartons

List all cartons with search, filter, and sort

GET
/v0/inventory/cartons/:id

Get a single carton by ID

GET
/v0/inventory/cartons/:id/history

Get change history for a carton

POST
/v0/inventory/cartons

Create a new carton

PUT
/v0/inventory/cartons/:id

Update a carton (name only)

DELETE
/v0/inventory/cartons/:id

Delete a carton (soft-delete, must have 0 stock)

PATCH
/v0/inventory/cartons/:id/restore

Restore a previously deleted carton

List Cartons

Returns a paginated list of cartons. By default, deleted cartons are excluded.

Query Parameters

ParameterTypeDescription
searchstringPartial match on carton name, product name, or SKU
productIdstringFilter by product ID
includeDeletedbooleanInclude soft-deleted cartons (default: false)
sortBystringSort field: name, createdAt, updatedAt (default: createdAt)
sortOrderstringSort direction: asc or desc (default: desc)
skipnumberNumber of records to skip (default: 0)
takenumberNumber of records to return (default: 10, max: 50)
curl
curl "https://api.3plguys.com/v0/inventory/cartons?search=10-pack" \
-H "Authorization: Bearer <token>"
Node.js
const res = await fetch(
"https://api.3plguys.com/v0/inventory/cartons?search=10-pack",
{ headers: { Authorization: `Bearer ${token}` } }
);
const cartons = await res.json();
Response
[
{
"id": "1",
"name": "10-Pack Case",
"contents": [
{
"productId": "1",
"productName": "Egg Shells",
"sku": "ABC123",
"quantity": 10
}
],
"dimensions": { "length": 12, "width": 10, "height": 8, "units": "inch" },
"weight": { "amount": 5, "units": "pound" },
"createdAt": "2025-01-15T08:30:00.000Z",
"updatedAt": "2025-02-20T14:00:00.000Z",
"deletedAt": null
}
]

Get Carton

Retrieve a single carton by its ID. Returns 404 if the carton does not exist or belongs to another organization.

GET /v0/inventory/cartons/1
{
"id": "1",
"name": "10-Pack Case",
"contents": [
{
"productId": "1",
"productName": "Egg Shells",
"sku": "ABC123",
"quantity": 10
}
],
"dimensions": { "length": 12, "width": 10, "height": 8, "units": "inch" },
"weight": { "amount": 5, "units": "pound" },
"createdAt": "2025-01-15T08:30:00.000Z",
"updatedAt": "2025-02-20T14:00:00.000Z",
"deletedAt": null
}

Create Carton

Request Body

ParameterTypeDescription
namestringCarton name (auto-generated if omitted)
contents*arrayProducts in this carton (currently limited to 1 item)
contents[].productId*stringProduct ID
contents[].quantity*numberUnits of this product per carton (min: 1)
dimensions*objectPhysical dimensions of the carton
dimensions.length*numberLength
dimensions.width*numberWidth
dimensions.height*numberHeight
dimensions.units*stringUnit of measurement (e.g. inch, millimeter)
weight*objectWeight of the carton
weight.amount*numberWeight value
weight.units*stringUnit of measurement (e.g. pound, gram)
curl
curl -X POST "https://api.3plguys.com/v0/inventory/cartons" \
-H "Authorization: Bearer <token>" \
-H "Content-Type: application/json" \
-d '{
"name": "10-Pack Case",
"contents": [{ "productId": "1", "quantity": 10 }],
"dimensions": { "length": 12, "width": 10, "height": 8, "units": "inch" },
"weight": { "amount": 5, "units": "pound" }
}'
Node.js
const res = await fetch("https://api.3plguys.com/v0/inventory/cartons", {
method: "POST",
headers: {
Authorization: `Bearer ${token}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
name: "10-Pack Case",
contents: [{ productId: "1", quantity: 10 }],
dimensions: { length: 12, width: 10, height: 8, units: "inch" },
weight: { amount: 5, units: "pound" },
}),
});
const carton = await res.json();
Request Body
{
"name": "10-Pack Case",
"contents": [
{ "productId": "1", "quantity": 10 }
],
"dimensions": { "length": 12, "width": 10, "height": 8, "units": "inch" },
"weight": { "amount": 5, "units": "pound" }
}
Response
{
"id": "3",
"name": "10-Pack Case",
"contents": [
{
"productId": "1",
"productName": "Egg Shells",
"sku": "ABC123",
"quantity": 10
}
],
"dimensions": { "length": 12, "width": 10, "height": 8, "units": "inch" },
"weight": { "amount": 5, "units": "pound" },
"createdAt": "2025-03-04T10:00:00.000Z",
"updatedAt": "2025-03-04T10:00:00.000Z",
"deletedAt": null
}

Immutable after creation

Contents, dimensions, and weight cannot be changed after the carton is created. If you need different specs, create a new carton and delete the old one. Only the carton name can be updated via PUT.

Update Carton

Only the carton name can be updated.

Request Body

ParameterTypeDescription
name*stringNew carton name (min 2 chars)
PUT /v0/inventory/cartons/3
{
"name": "10-Pack Shipping Case"
}

Delete Carton

Soft-deletes a carton. The carton must have zero stock across all warehouses. Deleted cartons are excluded from list results unless includeDeleted=true is passed.

DELETE /v0/inventory/cartons/3
{
"id": "3",
"name": "10-Pack Shipping Case",
"contents": [ ... ],
"dimensions": { ... },
"weight": { ... },
"createdAt": "2025-03-04T10:00:00.000Z",
"updatedAt": "2025-03-04T12:00:00.000Z",
"deletedAt": "2025-03-04T12:00:00.000Z"
}

Restore Carton

Restores a previously deleted carton, making it active again.

PATCH /v0/inventory/cartons/3/restore
{
"id": "3",
"name": "10-Pack Shipping Case",
...
"deletedAt": null
}

Carton History

Returns a paginated list of change events for a carton, including creation, name changes, stock count updates, deletes, and restores. Only publicly visible entries are returned.

Query Parameters

ParameterTypeDescription
skipnumberNumber of records to skip (default: 0)
takenumberNumber of records to return (default: 10, max: 50)
curl
curl "https://api.3plguys.com/v0/inventory/cartons/1/history?take=10" \
-H "Authorization: Bearer <token>"
Node.js
const res = await fetch(
`https://api.3plguys.com/v0/inventory/cartons/${cartonId}/history?take=10`,
{ headers: { Authorization: `Bearer ${token}` } }
);
const history = await res.json();
Python
res = httpx.get(
f"https://api.3plguys.com/v0/inventory/cartons/{carton_id}/history",
params={"take": 10},
headers={"Authorization": f"Bearer {token}"},
)
history = res.json()
Response
[
{
"id": "20",
"type": "admin",
"description": "Updated carton count '10' changed to '15' for '10-Pack Case' carton type.",
"createdAt": "2026-03-02T08:00:00.000Z"
},
{
"id": "5",
"type": "customer",
"description": "Created carton type \"10-Pack Case\" (10 units per carton)",
"createdAt": "2025-01-15T08:30:00.000Z"
}
]

Response Fields

ParameterTypeDescription
id*stringHistory entry ID
type*stringWho made the change: system, customer, or admin
description*stringHuman-readable description of what changed
createdAt*ISO 8601When the change occurred

Error Responses

400Only one product per carton is supported at this time

Each carton type can only contain one product. Provide a single item in the contents array.

400Product not found

The product ID in contents does not exist or does not belong to your organization.

400Cannot delete a carton that still has stock

Returned when attempting to delete a carton that has inventory in any warehouse.

404Carton not found

The carton ID does not exist or does not belong to your organization.