API Reference
Build custom workflows and integrations with our REST API. Manage cases, containers, packs, and entities programmatically or with AI.
Introduction
Base URL
https://steady-beagle-345.convex.site/api/v1- All dimensions are in meters, weights in kilograms
- Rate limited to 200 requests/minute with 300 burst capacity
orgIdis automatically inferred from the API key- Successful responses are wrapped in
{ success: true, data }
Core concepts
Truck Packer's data splits into two layers: a reusable library of definitions, and the load plans you build from them.
Library — your reusable definitions
- Cases are box types (a rack, a pelican case, a subwoofer) with real-world dimensions and weight. Define each once and reuse it across every load plan.
- Case Categories group cases by kind (Fragile, Audio, Rigging) with a color. A case must reference a category, so create categories first.
- Containers are the trucks, trailers, and shipping containers you load into — also reusable definitions with dimensions and a payload capacity.
Load plans — the actual arrangement
- A Pack is a single load plan — a workspace holding one or more containers and the cases arranged inside them.
- Entities are the things actually placed in a pack's 3D scene: a
caseentity is one box at a position and rotation, acontainerentity is the truck it sits in, andgroup/textentities organize and label the scene.
Key distinction: a case is not an entity
Creating a case defines a type — it doesn't place anything in a truck. To put it in a load plan you create an entity of that type inside a pack. Entities are self-contained: a case entity isn't linked to a library case by ID — it carries its own size and caseData, so you pass the dimensions and properties when you create it.
Typical workflow: build a load plan
POST /case-categories— create your categories.POST /cases— define your inventory, each referencing a category.POST /packs— create a load plan.POST /entities:batchCreate— place a container and the cases at their positions.GET /packs/:id/entities— read the finished plan back.
Authentication
All requests require a Bearer token in the Authorization header. Generate an API key from Settings → API Keys in the Truck Packer app. Keys start with tp_.
Header format
AuthorizationstringrequiredBearer token in the format: Bearer tp_your-api-key
curl https://steady-beagle-345.convex.site/api/v1/cases \
-H "Authorization: Bearer tp_your-api-key"Responses & Errors
Every response is JSON. Successful responses are wrapped in a success envelope; creates return 201 with the new record's _id (batch creates return an ids array). Errors return a success: false envelope with a message.
Status codes
400Bad request — malformed JSON, missing parameter, or per-pack entity limit (600) exceeded401Missing or invalid API key404Resource not found422Validation error (check required fields and types)429Rate limit exceeded (includes a retryAfter value)500Server error// Success
{
"success": true,
"data": { "_id": "..." }
}
// Error
{
"success": false,
"error": "Case not found"
}Use with AI
Give any LLM or AI agent full knowledge of the Truck Packer REST API. Copy the skill file below into your agent's context, or download the raw markdown.
Works with:
- Claude — paste into a Project's custom instructions or as a tool description
- ChatGPT / GPTs — add as knowledge or instructions
- Custom agents — include in your agent's system prompt or as a retrieval document
---
name: truck-packer-api
description: |
Use this skill whenever the user wants to interact with Truck Packer — a 3D truck/container load planning platform. This includes creating, listing, updating, or deleting cases (box types), case categories, containers (trucks/trailers), packs (loading plans), or entities (3D-positioned items within a pack). Also trigger when the user mentions "truck packer", "load plan", "packing API", wants to import gear/inventory into Truck Packer, build load plans programmatically, or manage their Truck Packer data in any way. If the user references cases, containers, or packs in a logistics/touring context, this skill is likely what they need.
---
# Truck Packer REST API
You have access to the Truck Packer REST API. Use this reference to make API calls on behalf of the user via `curl` or similar HTTP tools in the shell.
## Authentication
All requests require a Bearer token. API keys start with `tp_` and are generated from **Settings → API Keys** in the Truck Packer app (available on the Business plan).
```
Authorization: Bearer tp_<YOUR_API_KEY>
```
## Base URL
```
https://steady-beagle-345.convex.site/api/v1
```
## Conventions
- Dimensions are in **meters**, weights in **kilograms**
- Rate limit: 200 req/min, 300 burst
- `orgId` is inferred from the API key — never include it in request bodies
- Successful responses are wrapped: `{ "success": true, "data": ... }`. Creates return `201` with `{ "success": true, "data": { "_id": "..." } }`; batch creates return `{ "success": true, "data": { "ids": [...] } }`
- All error responses return `{ "success": false, "error": "..." }`
- **`canRotate3d` defaults to `false`** — unless the source data explicitly says an item can be tipped/rotated, assume it cannot. Most road cases, racks, and consoles must stay upright.
---
## Cases
Cases are box types that can be loaded into containers.
| Action | Method | Endpoint |
|---------------|----------|---------------------|
| List all | `GET` | `/api/v1/cases` |
| Get by ID | `GET` | `/api/v1/cases/:id` |
| Create | `POST` | `/api/v1/cases` |
| Update | `PUT` | `/api/v1/cases/:id` |
| Delete | `DELETE` | `/api/v1/cases/:id` |
### Create Case body
```json
{
"name": "string (required)",
"dx": "number (required) — length in meters",
"dy": "number (required) — width in meters",
"dz": "number (required) — height in meters",
"canRotate3d": "boolean (required)",
"categoryId": "string (required)",
"description": "string (optional)",
"manufacturer": "string (optional)",
"weight": "number (optional) — kilograms"
}
```
Update accepts the same fields, all optional — include only what you want to change.
---
## Case Categories
Categories group cases by type with a color for visual identification.
| Action | Method | Endpoint |
|---------------|----------|------------------------------|
| List all | `GET` | `/api/v1/case-categories` |
| Create | `POST` | `/api/v1/case-categories` |
| Update | `PUT` | `/api/v1/case-categories/:id`|
| Delete | `DELETE` | `/api/v1/case-categories/:id`|
### Create Category body
```json
{
"name": "string (required)",
"colorHex": "string (required) — e.g. '#FF4444'"
}
```
---
## Containers
Containers are the trucks, trailers, or shipping containers that cases are loaded into.
| Action | Method | Endpoint |
|---------------|----------|--------------------------|
| List all | `GET` | `/api/v1/containers` |
| Get by ID | `GET` | `/api/v1/containers/:id` |
| Create | `POST` | `/api/v1/containers` |
| Update | `PUT` | `/api/v1/containers/:id` |
| Delete | `DELETE` | `/api/v1/containers/:id` |
### Create Container body
```json
{
"name": "string (required)",
"type": "string (required) — one of: dry_container, boxcar, flatbed_trailer, step_deck_trailer, dry_van_trailer, reefer_van_trailer, box_truck, uld",
"dx": "number (required) — length in meters",
"dy": "number (required) — width in meters",
"dz": "number (required) — height in meters",
"description": "string (optional)",
"code": "string (optional) — e.g. ISO 6346 (45G1) for sea, IATA ULD (PMC) for air",
"payloadCapacity": "number (optional) — kilograms"
}
```
---
## Packs
Packs are loading plans — workspaces where cases are arranged inside containers.
| Action | Method | Endpoint |
|----------------|----------|-----------------------------|
| List all | `GET` | `/api/v1/packs` |
| Get by ID | `GET` | `/api/v1/packs/:id` |
| Get entities | `GET` | `/api/v1/packs/:id/entities`|
| Create | `POST` | `/api/v1/packs` |
| Delete | `DELETE` | `/api/v1/packs/:id` |
### Create Pack body
```json
{
"name": "string (optional)",
"folderId": "string (optional)"
}
```
Deleting a pack permanently removes all its entities, export views, and thumbnails.
---
## Entities
Entities are scene graph nodes within a pack — cases, containers, groups, and text labels positioned in 3D space. A pack can hold at most **600 entities**; a batch create that would exceed this returns `400`.
| Action | Method | Endpoint |
|----------------|--------|-----------------------------------|
| Get by pack | `GET` | `/api/v1/entities?packId=PACK_ID` |
| Batch create | `POST` | `/api/v1/entities:batchCreate` |
| Batch update | `POST` | `/api/v1/entities:batchUpdate` |
| Batch delete | `POST` | `/api/v1/entities:batchDelete` |
All entities in a single batch request must belong to the same pack.
### Batch Create body
```json
{
"entities": [
{
"name": "string (required)",
"type": "string (required) — case | container | group | text",
"packId": "string (required)",
"visible": "boolean (required)",
"childrenIds": "string[] (required) — empty array for leaf nodes",
"position": "{ x, y, z } (required) — meters",
"quaternion": "{ x, y, z, w } (required) — use {0,0,0,1} for no rotation",
"size": "{ x, y, z } (required) — meters",
"caseData": "{ weight?, manufacturer?, canRotate3d, categoryId } (required for case type)",
"containerData": "{ type, payloadCapacity?, code?, description? } (required for container type)",
"groupData": "{ colorHex } (required for group type)",
"textData": "{ text, fontSize, color, textAlign, outlineWidth, outlineColor } (required for text type — all six fields required; textAlign is one of left | center | right | justify)"
}
]
}
```
Each entity must include the type-specific data object that matches its `type` (a `case` needs `caseData`, a `container` needs `containerData`, etc.). Entities missing their type-specific data are dropped from the batch.
### Batch Update body
```json
{
"packId": "string (required)",
"entities": [
{
"id": "string (required)",
"name": "string",
"visible": "boolean",
"position": "{ x, y, z }",
"quaternion": "{ x, y, z, w }",
"size": "{ x, y, z }",
"...other optional fields"
}
]
}
```
### Batch Delete body
```json
{
"packId": "string (required)",
"ids": ["ENTITY_ID_1", "ENTITY_ID_2"]
}
```
Children are deleted recursively.
---
## Coordinate System
Truck Packer uses a **Y-up** coordinate system:
- **X** = length (left/right, along the trailer's long axis)
- **Y** = height (up/down, vertical)
- **Z** = width/depth (front/back)
Both `size` and `position` use this convention. The `position` field is the entity's **center point**, so to place an entity on the ground, set `position.y = size.y / 2`.
## Default Container
Unless the user specifies otherwise, always add a **53' dry van trailer** to new packs. Standard dimensions: 16.154m (L) x 2.591m (W) x 2.743m (H).
```python
trailer_entity = {
"name": "53' Dry Van Trailer",
"type": "container",
"packId": pack_id,
"visible": True,
"childrenIds": [],
"position": {"x": 16.154 / 2, "y": 2.743 / 2, "z": 2.591 / 2},
"quaternion": {"x": 0, "y": 0, "z": 0, "w": 1},
"size": {"x": 16.154, "y": 2.743, "z": 2.591},
"containerData": {"type": "dry_van_trailer"}
}
```
## Parsing Pull Sheets / Manifests
### Weight calculation
Many vendor manifests (e.g. Clair Global) list the weight of the **empty case** on the "Piece" line, not the loaded weight. The items indented below a piece are what goes inside it. When building entities, the weight for each piece should be the **sum of the piece's own weight plus all sub-items listed beneath it**, up until the next piece. This gives the realistic loaded weight for packing and weight distribution.
### Identifying pieces
A "Piece" line is any row that has dimensions (L, W, H). Rows without dimensions are sub-items that belong to the piece above them. Items with a "Piece #X:" prefix in the description are the physical cases/containers that get loaded onto the truck. Sub-items (indented or without dimensions) are contents that live inside the piece and contribute to its total weight.
### Dolly handling in pull sheets
Vendors like Clair Global often list dollies as separate line items with their own piece number and dimensions. These are not standalone cargo — a dolly is a wheeled platform that goes under a specific speaker or rack for transport. When parsing, identify dolly items (anything with "dolly" in the name) and pair them with their parent item by matching model numbers or name prefixes. In the load plan, the dolly should be placed on the floor with its parent item stacked directly on top, forming a single logical unit. Don't place dollies as independent floor items scattered around the truck.
---
## Packing Strategy — Pack Like a Human
When creating a pack from scratch, always generate a fully positioned load plan (not just entities at origin). The goal is a realistic pack that a crew could actually load. Follow these principles:
### 1. Build rows across the trailer width (Z axis)
Pack cases into **rows** that span the width of the trailer (Z axis, ~2.59m for a 53' dry van). Each row is a cross-section of the truck at a given X position. Fill a row across Z before advancing along X to the next row. Keep cases flush against each other within a row — no wasted gaps.
### 2. Smart stacking — floor first, stack only when necessary
**Default behavior: everything on the floor.** Place all items on the trailer floor in a single layer first. Do NOT stack similar cases by default — subwoofers, racks, road cases, etc. all go on the floor unless they physically won't fit.
**Overflow stacking (last resort only):** If the single-layer floor plan extends past the end of the trailer (total X depth exceeds trailer length), THEN start stacking similar cases to reclaim floor space. Only stack cases of the same type or very similar footprint on top of each other — e.g. two subwoofers, two half-packs (~24"×48" / ~0.61m×1.22m), or two quarter-packs (~24"×24" / ~0.61m×0.61m). This is a space-recovery measure, not a default packing behavior.
**Auto-stackable small items**: Items with a footprint smaller than roughly a quarter-pack case (~24"×24" / ~0.61m×0.61m) ARE stackable by default regardless of overflow. This includes pelican cases, small road cases, accessory boxes, tops, lids, and similar. Items that aren't particularly tall (under ~0.5m / 20" height) can also lay across multiple cases beneath them — they don't need a single matching footprint underneath. Think of how a crew would toss a CO12 top grip across one or two nearby stacks, or set a CP218 top on a convenient stack. That's the behavior to replicate.
**Large items**: Big road cases, racks, and consoles should never stack on smaller footprints. Don't put a 4' case on top of a 2' case. They may only stack on same-size or larger footprints, and only during the overflow stacking pass.
### 2b. Dollies go UNDER their parent items — not standalone
Vendors like Clair Global often list dollies as separate line items on a pull sheet. A dolly is not a standalone piece of cargo — it's a wheeled base that a speaker cabinet, rack, or distro sits on for rolling. When building a load plan, place the dolly on the floor first, then place its parent item directly on top of it. The dolly's Y position is `dolly.size.y / 2` (on the ground), and the item riding on it gets `position.y = dolly.size.y + item.size.y / 2`.
Match dollies to their parent items by name similarity — for example, a "Stakrak Dolly" goes under the "Stakrak Distro", a "CS218 Dolly" goes under "CS218" speakers. If the dolly name contains a model prefix that matches another item, pair them. When in doubt, look at the pull sheet grouping — dollies are usually listed near the items they belong to.
### 3. Tight rows, minimal gaps
Cases should be **flush against each other** — no spacing between items in a row. The truck is moving down the road; you want everything snug so nothing shifts. Each row fills across Z (trailer width) with zero gap, and the next row starts immediately at the back of the deepest item in the previous row.
### 4. Flat rows for strapping
Each row should present a **flat face** along the X axis so load bars / straps sit cleanly. Group items with similar X-depth into the same row. Don't mix a 1.7m-deep console with a 0.6m-deep rack in the same row.
### 5. Group by category
Keep similar types of gear together when possible — all racks in one section, all workboxes together, all pelican cases together, etc. This mirrors how crews actually load and makes it faster to find things on-site.
### 6. Load bars every 2.4m – 4.8m (8' – 16')
After every 2.4m to 4.8m of packed depth along the X axis, leave a small visual gap (~0.05m) to represent where a load bar or strap would go. This is standard practice to prevent cargo shift during transit.
### Packing algorithm
Before placing anything, do a pre-processing pass:
**Pre-pass: pair dollies with their parent items.** Scan all items for anything with "dolly" in the name. Match each dolly to its parent item by model prefix or name similarity (e.g. "Stakrak Dolly" → "Stakrak Distro"). Treat each dolly+parent as a single combined unit for placement — the dolly goes on the floor, the parent rides on top. Remove paired dollies from the main item list so they aren't placed separately.
**Pre-pass: classify stackability.** Mark items as auto-stackable if their footprint is under ~0.61m×0.61m (24"×24") or they're short (under ~0.5m tall). These will be placed on top of floor items after the main layout. All other items default to floor placement.
Then sort the remaining items by category, then by X-depth (similar depths together for flat rows), then by weight (heaviest first). Place floor items:
1. For each item (including dolly+parent combos), try to fit it in the current row across Z
2. If z_cursor + item_width > trailer_width, the row is full — advance x_cursor by the row's depth and start fresh
3. Insert a load bar gap (~0.05m) every 2.4–4.8m along X
4. Place flush: z_cursor += item_width (no gap)
After floor items are placed, do a stacking pass for auto-stackable small items — place each one on top of the nearest floor item (or stack) that can support it, preferring items in the same category. Small items can span across two adjacent cases if needed.
**Overflow check:** After placing everything (floor + small-item stacking), check if the total packed X depth exceeds the trailer length. If it does, perform an **overflow stacking pass**: identify groups of same-type cases (e.g. multiple subwoofers, multiple half-packs, multiple quarter-packs) and stack duplicates on top of each other to free floor space. Only stack cases with matching or very similar footprints. Re-run the floor layout with the freed space. Repeat until the load fits or no more valid stacking options remain.
The priorities: tight rows, zero gaps, dollies under their parents, everything on the floor unless it won't fit, small items stacked on top, overflow stacking of similar cases only when needed, group by category, flat faces for strapping, load bars at intervals.
---
## Common Workflows
### Import cases from an external system
1. `POST /case-categories` — create categories first
2. `POST /cases` — create cases referencing those category IDs
### Build a load plan programmatically
1. `POST /packs` — create a pack
2. `POST /entities:batchCreate` — add a 53' dry van trailer (default) plus all cases
3. Parse the pull sheet: sum sub-item weights into each piece's total, set `canRotate3d: false` by default
4. Position entities using the packing strategy above — rows, stacking, category grouping, load bars
### Sync inventory
1. `GET /cases` — fetch current cases
2. `PUT /cases/:id` — update changed ones
3. `POST /cases` — create new ones
4. `DELETE /cases/:id` — remove deleted ones
---
## Error Codes
| Status | Meaning |
|--------|-------------------------------------------------------------------------|
| 400 | Bad request — malformed JSON, missing required parameter, or per-pack entity limit exceeded |
| 401 | Missing or invalid API key |
| 404 | Resource not found |
| 422 | Validation error (check required fields and types) |
| 429 | Rate limit exceeded (includes a `retryAfter` value) |
| 500 | Server error |
Cases
Cases are reusable box-type definitions in your library — a rack, a pelican case, a subwoofer — with real-world dimensions (dx/dy/dz in meters) and weight (kg). Each case references a category and can be reused across any pack. Defining a case does not place it in a truck; to load it, add a case entity to a pack.
List Cases
/api/v1/casesReturns all cases belonging to the authenticated organization.
curl https://steady-beagle-345.convex.site/api/v1/cases \
-H "Authorization: Bearer tp_your-api-key"Get Case by ID
/api/v1/cases/:idReturns a single case by its ID.
Parameters
idstringrequiredPathThe case ID.
curl https://steady-beagle-345.convex.site/api/v1/cases/CASE_ID \
-H "Authorization: Bearer tp_your-api-key"Create Case
/api/v1/casesCreate a new case (box type). The orgId is inferred from the API key.
Parameters
namestringrequiredBodyCase name.
dxnumberrequiredBodyLength in meters.
dynumberrequiredBodyWidth in meters.
dznumberrequiredBodyHeight in meters.
canRotate3dbooleanrequiredBodyWhether the case can rotate freely on any axis.
categoryIdstringrequiredBodyID of the case category.
descriptionstringBodyOptional description.
manufacturerstringBodyManufacturer name.
weightnumberBodyWeight in kilograms.
curl -X POST https://steady-beagle-345.convex.site/api/v1/cases \
-H "Authorization: Bearer tp_your-api-key" \
-H "Content-Type: application/json" \
-d '{
"name": "Widget Box",
"description": "Standard shipping box",
"manufacturer": "Acme Corp",
"weight": 12.5,
"dx": 0.5,
"dy": 0.3,
"dz": 0.4,
"canRotate3d": true,
"categoryId": "CATEGORY_ID"
}'Update Case
/api/v1/cases/:idUpdate an existing case. Pass the case ID in the URL path.
Parameters
idstringrequiredPathThe case ID.
namestringBodyCase name.
descriptionstringBodyDescription.
manufacturerstringBodyManufacturer name.
weightnumberBodyWeight in kilograms.
dxnumberBodyLength in meters.
dynumberBodyWidth in meters.
dznumberBodyHeight in meters.
canRotate3dbooleanBodyWhether AutoPack can rotate freely.
categoryIdstringBodyCase category ID.
curl -X PUT https://steady-beagle-345.convex.site/api/v1/cases/CASE_ID \
-H "Authorization: Bearer tp_your-api-key" \
-H "Content-Type: application/json" \
-d '{
"name": "Updated Widget Box",
"dx": 0.6,
"dy": 0.35,
"dz": 0.45,
"canRotate3d": false,
"categoryId": "CATEGORY_ID"
}'Delete Case
/api/v1/cases/:idPermanently delete a case by its ID.
Parameters
idstringrequiredPathThe case ID.
curl -X DELETE https://steady-beagle-345.convex.site/api/v1/cases/CASE_ID \
-H "Authorization: Bearer tp_your-api-key"Case Categories
Case categories group cases by kind (e.g., Fragile, Audio, Rigging) with a color for visual identification in the 3D scene. Every case must reference a category, so create your categories before creating cases.
List Case Categories
/api/v1/case-categoriesReturns all case categories for the authenticated organization.
curl https://steady-beagle-345.convex.site/api/v1/case-categories \
-H "Authorization: Bearer tp_your-api-key"Create Case Category
/api/v1/case-categoriesCreate a new case category.
Parameters
namestringrequiredBodyCategory name.
colorHexstringrequiredBodyHex color code (e.g. "#FF4444").
curl -X POST https://steady-beagle-345.convex.site/api/v1/case-categories \
-H "Authorization: Bearer tp_your-api-key" \
-H "Content-Type: application/json" \
-d '{
"name": "Fragile",
"colorHex": "#FF4444"
}'Update Case Category
/api/v1/case-categories/:idUpdate an existing case category.
Parameters
idstringrequiredPathCategory ID.
namestringBodyCategory name.
colorHexstringBodyHex color code.
curl -X PUT https://steady-beagle-345.convex.site/api/v1/case-categories/CATEGORY_ID \
-H "Authorization: Bearer tp_your-api-key" \
-H "Content-Type: application/json" \
-d '{
"name": "Very Fragile",
"colorHex": "#FF0000"
}'Delete Case Category
/api/v1/case-categories/:idDelete a case category by its ID.
Parameters
idstringrequiredPathCategory ID.
curl -X DELETE https://steady-beagle-345.convex.site/api/v1/case-categories/CATEGORY_ID \
-H "Authorization: Bearer tp_your-api-key"Containers
Containers are reusable definitions of the trucks, trailers, and shipping containers you load into, with dimensions (meters) and an optional payload capacity (kg). Like cases, they live in your library and are placed into a pack as container entities. The type field must be one of the eight supported container types.
List Containers
/api/v1/containersReturns all containers for the authenticated organization.
curl https://steady-beagle-345.convex.site/api/v1/containers \
-H "Authorization: Bearer tp_your-api-key"Get Container by ID
/api/v1/containers/:idReturns a single container by its ID.
Parameters
idstringrequiredPathContainer ID.
curl https://steady-beagle-345.convex.site/api/v1/containers/CONTAINER_ID \
-H "Authorization: Bearer tp_your-api-key"Create Container
/api/v1/containersCreate a new container (truck/trailer/shipping container).
Parameters
namestringrequiredBodyContainer name.
typestringrequiredBodyOne of: dry_container, boxcar, flatbed_trailer, step_deck_trailer, dry_van_trailer, reefer_van_trailer, box_truck, uld.
dxnumberrequiredBodyLength in meters.
dynumberrequiredBodyWidth in meters.
dznumberrequiredBodyHeight in meters.
descriptionstringBodyOptional description.
codestringBodyOptional code identifier.
payloadCapacitynumberBodyMax payload in kilograms.
curl -X POST https://steady-beagle-345.convex.site/api/v1/containers \
-H "Authorization: Bearer tp_your-api-key" \
-H "Content-Type: application/json" \
-d '{
"name": "53ft Dry Van",
"description": "Standard 53-foot dry van trailer",
"code": "DV-53",
"type": "dry_van_trailer",
"dx": 16.15,
"dy": 2.49,
"dz": 2.59,
"payloadCapacity": 20000
}'Update Container
/api/v1/containers/:idUpdate an existing container.
Parameters
idstringrequiredPathContainer ID.
namestringBodyContainer name.
descriptionstringBodyDescription.
codestringBodyCode identifier.
typestringBodyContainer type.
dxnumberBodyLength in meters.
dynumberBodyWidth in meters.
dznumberBodyHeight in meters.
payloadCapacitynumberBodyMax payload in kg.
curl -X PUT https://steady-beagle-345.convex.site/api/v1/containers/CONTAINER_ID \
-H "Authorization: Bearer tp_your-api-key" \
-H "Content-Type: application/json" \
-d '{
"name": "53ft Reefer",
"type": "reefer_van_trailer",
"dx": 16.15,
"dy": 2.49,
"dz": 2.59,
"payloadCapacity": 18000
}'Delete Container
/api/v1/containers/:idPermanently delete a container by its ID.
Parameters
idstringrequiredPathContainer ID.
curl -X DELETE https://steady-beagle-345.convex.site/api/v1/containers/CONTAINER_ID \
-H "Authorization: Bearer tp_your-api-key"Packs
Packs are load plans — each one is a workspace holding one or more containers and the cases arranged inside them. A pack’s contents are its entities: create a pack, then batch-create entities to fill it. Deleting a pack removes all of its entities too.
List Packs
/api/v1/packsReturns all packs for the authenticated organization.
curl https://steady-beagle-345.convex.site/api/v1/packs \
-H "Authorization: Bearer tp_your-api-key"Get Pack by ID
/api/v1/packs/:idReturns a single pack by its ID.
Parameters
idstringrequiredPathThe pack ID.
curl https://steady-beagle-345.convex.site/api/v1/packs/PACK_ID \
-H "Authorization: Bearer tp_your-api-key"Get Pack Entities
/api/v1/packs/:id/entitiesReturns all entities (cases, containers, groups, text) within a specific pack. Excludes soft-deleted entities.
Parameters
idstringrequiredPathThe pack ID.
curl https://steady-beagle-345.convex.site/api/v1/packs/PACK_ID/entities \
-H "Authorization: Bearer tp_your-api-key"Create Pack
/api/v1/packsCreate a new pack (loading plan).
Parameters
namestringBodyPack name.
folderIdstringBodyOptional folder ID to place the pack in.
curl -X POST https://steady-beagle-345.convex.site/api/v1/packs \
-H "Authorization: Bearer tp_your-api-key" \
-H "Content-Type: application/json" \
-d '{
"name": "Warehouse Shipment #42"
}'Delete Pack
/api/v1/packs/:idPermanently delete a pack and all its entities, export views, and preview thumbnails.
Parameters
idstringrequiredPathThe pack ID.
curl -X DELETE https://steady-beagle-345.convex.site/api/v1/packs/PACK_ID \
-H "Authorization: Bearer tp_your-api-key"Entities
Entities are the scene graph nodes within a pack — cases, containers, groups, and text labels positioned in 3D space. Each entity carries a type-specific data object (caseData, containerData, groupData, or textData) matching its type.
Entity types
Every entity has a type and a matching type-specific data object. Set type to one of:
casea box to load — needscaseDatacontainera truck/trailer — needscontainerDatagroupa grouping node — needsgroupDatatexta 3D text label (aisle markers, doors, load-in zones) — needstextDatawithtext,fontSize,color,textAlign,outlineWidth, andoutlineColor
Create any type — including text labels — with entities:batchCreate below (the example includes a text label).
Get Entities by Pack ID
/api/v1/entities?packId=:packIdReturns all entities for a specific pack. The packId query parameter is required.
Parameters
packIdstringrequiredQueryThe pack ID to fetch entities for.
curl "https://steady-beagle-345.convex.site/api/v1/entities?packId=PACK_ID" \
-H "Authorization: Bearer tp_your-api-key"Batch Create Entities
/api/v1/entities:batchCreateBatch create entities within a pack.
Parameters
entitiesarrayrequiredBodyArray of entity objects to create.
entities[].namestringrequiredBodyEntity name.
entities[].typestringrequiredBodyOne of: case, container, group, text.
entities[].packIdstringrequiredBodyPack ID this entity belongs to.
entities[].visiblebooleanrequiredBodyWhether the entity is visible.
entities[].childrenIdsstring[]requiredBodyArray of child entity IDs (empty for leaf nodes).
entities[].position{ x, y, z }requiredBodyPosition in meters.
entities[].quaternion{ x, y, z, w }requiredBodyRotation quaternion. Use {0,0,0,1} for no rotation.
entities[].size{ x, y, z }requiredBodyDimensions in meters.
entities[].caseDataobjectBodyRequired when type=case. Fields: canRotate3d (boolean, required), categoryId (string, required), weight (number, kg), manufacturer (string).
entities[].containerDataobjectBodyRequired when type=container. Fields: type (string, required — same enum as containers), payloadCapacity (number, kg), code (string), description (string).
entities[].groupDataobjectBodyRequired when type=group. Fields: colorHex (string, required).
entities[].textDataobjectBodyRequired when type=text — renders a 3D text label. All six fields required: text (string), fontSize (number, meters), color (string, hex), textAlign (left | center | right | justify), outlineWidth (number, meters), outlineColor (string, hex).
curl -X POST https://steady-beagle-345.convex.site/api/v1/entities:batchCreate \
-H "Authorization: Bearer tp_your-api-key" \
-H "Content-Type: application/json" \
-d '{
"entities": [
{
"name": "Widget Box #1",
"type": "case",
"packId": "PACK_ID",
"visible": true,
"childrenIds": [],
"position": { "x": 0, "y": 0, "z": 0 },
"quaternion": { "x": 0, "y": 0, "z": 0, "w": 1 },
"size": { "x": 0.5, "y": 0.3, "z": 0.4 },
"caseData": {
"weight": 12.5,
"canRotate3d": true,
"categoryId": "CATEGORY_ID"
}
},
{
"name": "Shipping Label",
"type": "text",
"packId": "PACK_ID",
"visible": true,
"childrenIds": [],
"position": { "x": 0, "y": 1, "z": 0 },
"quaternion": { "x": 0, "y": 0, "z": 0, "w": 1 },
"size": { "x": 0.3, "y": 0.1, "z": 0.01 },
"textData": {
"text": "FRAGILE",
"fontSize": 0.15,
"color": "#FF0000",
"textAlign": "center",
"outlineWidth": 0.01,
"outlineColor": "#000000"
}
}
]
}'Batch Update Entities
/api/v1/entities:batchUpdateBatch update entities within a pack. Only include the fields you want to change.
Parameters
packIdstringrequiredBodyThe pack these entities belong to.
entitiesarrayrequiredBodyArray of partial entity updates.
entities[].idstringrequiredBodyID of the entity to update.
entities[].namestringBodyUpdated name.
entities[].visiblebooleanBodyUpdated visibility.
entities[].position{ x, y, z }BodyUpdated position in meters.
entities[].quaternion{ x, y, z, w }BodyUpdated rotation.
entities[].size{ x, y, z }BodyUpdated dimensions in meters.
entities[].descriptionstringBodyUpdated description.
entities[].caseData / containerData / groupData / textDataobjectBodyUpdated type-specific data. Pass the matching object for the entity type — e.g. textData to change a text label’s text, fontSize, color, textAlign, or outline.
curl -X POST https://steady-beagle-345.convex.site/api/v1/entities:batchUpdate \
-H "Authorization: Bearer tp_your-api-key" \
-H "Content-Type: application/json" \
-d '{
"packId": "PACK_ID",
"entities": [
{
"id": "ENTITY_ID",
"name": "Renamed Box #1",
"position": { "x": 1, "y": 0, "z": 0 },
"visible": false
}
]
}'Batch Delete Entities
/api/v1/entities:batchDeleteBatch delete entities and all their children from a pack. Child entities are automatically deleted recursively.
Parameters
packIdstringrequiredBodyThe pack these entities belong to.
idsstring[]requiredBodyArray of entity IDs to delete.
curl -X POST https://steady-beagle-345.convex.site/api/v1/entities:batchDelete \
-H "Authorization: Bearer tp_your-api-key" \
-H "Content-Type: application/json" \
-d '{
"packId": "PACK_ID",
"ids": ["ENTITY_ID_1", "ENTITY_ID_2"]
}'