DocsAPI Reference

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
  • orgId is 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 case entity is one box at a position and rotation, a container entity is the truck it sits in, and group / text entities 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

  1. POST /case-categories — create your categories.
  2. POST /cases — define your inventory, each referencing a category.
  3. POST /packs — create a load plan.
  4. POST /entities:batchCreate — place a container and the cases at their positions.
  5. 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

Authorizationstringrequired

Bearer token in the format: Bearer tp_your-api-key

cURL
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) exceeded
401Missing or invalid API key
404Resource not found
422Validation error (check required fields and types)
429Rate limit exceeded (includes a retryAfter value)
500Server error
Response shape
// 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
truck-packer-api.md
---
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

GET/api/v1/cases

Returns all cases belonging to the authenticated organization.

cURL
curl https://steady-beagle-345.convex.site/api/v1/cases \
  -H "Authorization: Bearer tp_your-api-key"

Get Case by ID

GET/api/v1/cases/:id

Returns a single case by its ID.

Parameters

idstringrequiredPath

The case ID.

cURL
curl https://steady-beagle-345.convex.site/api/v1/cases/CASE_ID \
  -H "Authorization: Bearer tp_your-api-key"

Create Case

POST/api/v1/cases

Create a new case (box type). The orgId is inferred from the API key.

Parameters

namestringrequiredBody

Case name.

dxnumberrequiredBody

Length in meters.

dynumberrequiredBody

Width in meters.

dznumberrequiredBody

Height in meters.

canRotate3dbooleanrequiredBody

Whether the case can rotate freely on any axis.

categoryIdstringrequiredBody

ID of the case category.

descriptionstringBody

Optional description.

manufacturerstringBody

Manufacturer name.

weightnumberBody

Weight in kilograms.

cURL
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

PUT/api/v1/cases/:id

Update an existing case. Pass the case ID in the URL path.

Parameters

idstringrequiredPath

The case ID.

namestringBody

Case name.

descriptionstringBody

Description.

manufacturerstringBody

Manufacturer name.

weightnumberBody

Weight in kilograms.

dxnumberBody

Length in meters.

dynumberBody

Width in meters.

dznumberBody

Height in meters.

canRotate3dbooleanBody

Whether AutoPack can rotate freely.

categoryIdstringBody

Case category ID.

cURL
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

DELETE/api/v1/cases/:id

Permanently delete a case by its ID.

Parameters

idstringrequiredPath

The case ID.

cURL
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

GET/api/v1/case-categories

Returns all case categories for the authenticated organization.

cURL
curl https://steady-beagle-345.convex.site/api/v1/case-categories \
  -H "Authorization: Bearer tp_your-api-key"

Create Case Category

POST/api/v1/case-categories

Create a new case category.

Parameters

namestringrequiredBody

Category name.

colorHexstringrequiredBody

Hex color code (e.g. "#FF4444").

cURL
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

PUT/api/v1/case-categories/:id

Update an existing case category.

Parameters

idstringrequiredPath

Category ID.

namestringBody

Category name.

colorHexstringBody

Hex color code.

cURL
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

DELETE/api/v1/case-categories/:id

Delete a case category by its ID.

Parameters

idstringrequiredPath

Category ID.

cURL
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

GET/api/v1/containers

Returns all containers for the authenticated organization.

cURL
curl https://steady-beagle-345.convex.site/api/v1/containers \
  -H "Authorization: Bearer tp_your-api-key"

Get Container by ID

GET/api/v1/containers/:id

Returns a single container by its ID.

Parameters

idstringrequiredPath

Container ID.

cURL
curl https://steady-beagle-345.convex.site/api/v1/containers/CONTAINER_ID \
  -H "Authorization: Bearer tp_your-api-key"

Create Container

POST/api/v1/containers

Create a new container (truck/trailer/shipping container).

Parameters

namestringrequiredBody

Container name.

typestringrequiredBody

One of: dry_container, boxcar, flatbed_trailer, step_deck_trailer, dry_van_trailer, reefer_van_trailer, box_truck, uld.

dxnumberrequiredBody

Length in meters.

dynumberrequiredBody

Width in meters.

dznumberrequiredBody

Height in meters.

descriptionstringBody

Optional description.

codestringBody

Optional code identifier.

payloadCapacitynumberBody

Max payload in kilograms.

cURL
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

PUT/api/v1/containers/:id

Update an existing container.

Parameters

idstringrequiredPath

Container ID.

namestringBody

Container name.

descriptionstringBody

Description.

codestringBody

Code identifier.

typestringBody

Container type.

dxnumberBody

Length in meters.

dynumberBody

Width in meters.

dznumberBody

Height in meters.

payloadCapacitynumberBody

Max payload in kg.

cURL
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

DELETE/api/v1/containers/:id

Permanently delete a container by its ID.

Parameters

idstringrequiredPath

Container ID.

cURL
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

GET/api/v1/packs

Returns all packs for the authenticated organization.

cURL
curl https://steady-beagle-345.convex.site/api/v1/packs \
  -H "Authorization: Bearer tp_your-api-key"

Get Pack by ID

GET/api/v1/packs/:id

Returns a single pack by its ID.

Parameters

idstringrequiredPath

The pack ID.

cURL
curl https://steady-beagle-345.convex.site/api/v1/packs/PACK_ID \
  -H "Authorization: Bearer tp_your-api-key"

Get Pack Entities

GET/api/v1/packs/:id/entities

Returns all entities (cases, containers, groups, text) within a specific pack. Excludes soft-deleted entities.

Parameters

idstringrequiredPath

The pack ID.

cURL
curl https://steady-beagle-345.convex.site/api/v1/packs/PACK_ID/entities \
  -H "Authorization: Bearer tp_your-api-key"

Create Pack

POST/api/v1/packs

Create a new pack (loading plan).

Parameters

namestringBody

Pack name.

folderIdstringBody

Optional folder ID to place the pack in.

cURL
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

DELETE/api/v1/packs/:id

Permanently delete a pack and all its entities, export views, and preview thumbnails.

Parameters

idstringrequiredPath

The pack ID.

cURL
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 — needs caseData
  • containera truck/trailer — needs containerData
  • groupa grouping node — needs groupData
  • texta 3D text label (aisle markers, doors, load-in zones) — needs textData with text, fontSize, color, textAlign, outlineWidth, and outlineColor

Create any type — including text labels — with entities:batchCreate below (the example includes a text label).

Get Entities by Pack ID

GET/api/v1/entities?packId=:packId

Returns all entities for a specific pack. The packId query parameter is required.

Parameters

packIdstringrequiredQuery

The pack ID to fetch entities for.

cURL
curl "https://steady-beagle-345.convex.site/api/v1/entities?packId=PACK_ID" \
  -H "Authorization: Bearer tp_your-api-key"

Batch Create Entities

POST/api/v1/entities:batchCreate

Batch create entities within a pack.

Parameters

entitiesarrayrequiredBody

Array of entity objects to create.

entities[].namestringrequiredBody

Entity name.

entities[].typestringrequiredBody

One of: case, container, group, text.

entities[].packIdstringrequiredBody

Pack ID this entity belongs to.

entities[].visiblebooleanrequiredBody

Whether the entity is visible.

entities[].childrenIdsstring[]requiredBody

Array of child entity IDs (empty for leaf nodes).

entities[].position{ x, y, z }requiredBody

Position in meters.

entities[].quaternion{ x, y, z, w }requiredBody

Rotation quaternion. Use {0,0,0,1} for no rotation.

entities[].size{ x, y, z }requiredBody

Dimensions in meters.

entities[].caseDataobjectBody

Required when type=case. Fields: canRotate3d (boolean, required), categoryId (string, required), weight (number, kg), manufacturer (string).

entities[].containerDataobjectBody

Required when type=container. Fields: type (string, required — same enum as containers), payloadCapacity (number, kg), code (string), description (string).

entities[].groupDataobjectBody

Required when type=group. Fields: colorHex (string, required).

entities[].textDataobjectBody

Required 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
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

POST/api/v1/entities:batchUpdate

Batch update entities within a pack. Only include the fields you want to change.

Parameters

packIdstringrequiredBody

The pack these entities belong to.

entitiesarrayrequiredBody

Array of partial entity updates.

entities[].idstringrequiredBody

ID of the entity to update.

entities[].namestringBody

Updated name.

entities[].visiblebooleanBody

Updated visibility.

entities[].position{ x, y, z }Body

Updated position in meters.

entities[].quaternion{ x, y, z, w }Body

Updated rotation.

entities[].size{ x, y, z }Body

Updated dimensions in meters.

entities[].descriptionstringBody

Updated description.

entities[].caseData / containerData / groupData / textDataobjectBody

Updated 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
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

POST/api/v1/entities:batchDelete

Batch delete entities and all their children from a pack. Child entities are automatically deleted recursively.

Parameters

packIdstringrequiredBody

The pack these entities belong to.

idsstring[]requiredBody

Array of entity IDs to delete.

cURL
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"]
  }'
Truck Packer REST API v1 · Backline Logic