Batch Packing

Submit hundreds or thousands of pack jobs in a single API call and poll for results asynchronously. Batch packing is ideal for overnight processing, bulk order fulfillment, and high-volume scenarios.

Prerequisites

Workflow overview

POST /batch  (submit jobs)  -->  202 Accepted + batchId
        |
        v
GET /batch/{batchId}  (poll for results)
        |
        v
    Results: completed / failed per order

Step 1: Submit a batch

Each batch contains an array of orders, where each order has its own packRequest. Maximum 10,000 orders per batch.

curl -X POST https://api.fractalpack.com/api/v1/batch \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: fpk_test_your_api_key" \
  -d '{
    "orders": [
      {
        "orderId": "ORD-2026-0001",
        "packRequest": {
          "items": [
            {
              "id": "WIDGET-LG-001",
              "length": 12,
              "width": 8,
              "height": 6,
              "weight": 2.5,
              "quantity": 3
            }
          ],
          "containers": [
            {
              "id": "BOX-MEDIUM",
              "length": 18,
              "width": 14,
              "height": 12,
              "maxWeight": 40
            }
          ],
          "allowMultipleBoxes": true
        }
      },
      {
        "orderId": "ORD-2026-0002",
        "packRequest": {
          "items": [
            {
              "id": "MONITOR-27IN",
              "length": 28,
              "width": 18,
              "height": 8,
              "weight": 12.0,
              "quantity": 1
            },
            {
              "id": "KEYBOARD-MECH",
              "length": 17,
              "width": 6,
              "height": 2,
              "weight": 2.1,
              "quantity": 1
            }
          ],
          "containers": [
            {
              "id": "BOX-LARGE",
              "length": 36,
              "width": 20,
              "height": 12,
              "maxWeight": 50
            }
          ],
          "allowMultipleBoxes": true
        }
      },
      {
        "orderId": "ORD-2026-0003",
        "packRequest": {
          "items": [
            {
              "id": "CABLE-USB-C",
              "length": 6,
              "width": 4,
              "height": 1,
              "weight": 0.1,
              "quantity": 10
            }
          ],
          "containers": [
            {
              "id": "BOX-SMALL",
              "length": 12,
              "width": 10,
              "height": 6,
              "maxWeight": 15
            }
          ]
        }
      }
    ],
    "webhookUrl": "https://hooks.example.com/batch-complete"
  }'

Response (202 Accepted)

{
  "batchId": "batch_x9y8z7w6",
  "status": "submitted",
  "totalOrders": 3,
  "statusUrl": "/api/v1/batch/batch_x9y8z7w6"
}

The batch is queued for asynchronous processing. If you provide a webhookUrl, a POST is sent to that URL when the batch completes.

Step 2: Poll for results

curl -X GET "https://api.fractalpack.com/api/v1/batch/batch_x9y8z7w6" \
  -H "X-Api-Key: fpk_test_your_api_key"

Response (in progress)

{
  "batchId": "batch_x9y8z7w6",
  "status": "processing",
  "totalOrders": 3,
  "completedOrders": 1,
  "failedOrders": 0,
  "pendingOrders": 2,
  "createdAt": "2026-04-03T22:00:00Z",
  "completedAt": null,
  "orders": [
    {
      "orderId": "ORD-2026-0001",
      "status": "completed",
      "result": {
        "algorithm": "ebAfit",
        "results": [
          {
            "containerId": "BOX-MEDIUM",
            "boxIndex": 0,
            "packedItems": [
              { "id": "WIDGET-LG-001", "weight": 2.5 },
              { "id": "WIDGET-LG-001", "weight": 2.5 },
              { "id": "WIDGET-LG-001", "weight": 2.5 }
            ],
            "unpackedItems": [],
            "volumeUtilizationPercent": 57.1,
            "totalWeight": 7.5
          }
        ]
      }
    },
    {
      "orderId": "ORD-2026-0002",
      "status": "pending"
    },
    {
      "orderId": "ORD-2026-0003",
      "status": "pending"
    }
  ],
  "nextPageToken": null,
  "hasMore": false
}

Response (completed)

{
  "batchId": "batch_x9y8z7w6",
  "status": "completed",
  "totalOrders": 3,
  "completedOrders": 3,
  "failedOrders": 0,
  "pendingOrders": 0,
  "createdAt": "2026-04-03T22:00:00Z",
  "completedAt": "2026-04-03T22:00:45Z",
  "orders": [ ... ],
  "nextPageToken": null,
  "hasMore": false
}

Batch status values: submitted, processing, completed.

Filtering by status

Retrieve only completed or failed orders:

curl -X GET "https://api.fractalpack.com/api/v1/batch/batch_x9y8z7w6?status=failed" \
  -H "X-Api-Key: fpk_test_your_api_key"

Pagination

For large batches, paginate through results with limit and after:

# First page
curl -X GET "https://api.fractalpack.com/api/v1/batch/batch_x9y8z7w6?limit=100" \
  -H "X-Api-Key: fpk_test_your_api_key"

# Next page (use nextPageToken from previous response)
curl -X GET "https://api.fractalpack.com/api/v1/batch/batch_x9y8z7w6?limit=100&after=ORD-2026-0100" \
  -H "X-Api-Key: fpk_test_your_api_key"

Step 3: Handle partial failures

Some orders may fail while others succeed:

{
  "batchId": "batch_x9y8z7w6",
  "status": "completed",
  "totalOrders": 500,
  "completedOrders": 497,
  "failedOrders": 3,
  "pendingOrders": 0,
  "orders": [
    {
      "orderId": "ORD-2026-0042",
      "status": "failed",
      "error": "No container can fit item OVERSIZED-PANEL (48x36x2 in)"
    },
    {
      "orderId": "ORD-2026-0199",
      "status": "failed",
      "error": "Total item quantity exceeds 500,000 limit"
    },
    {
      "orderId": "ORD-2026-0350",
      "status": "failed",
      "error": "Item WIDGET-LG-001 has invalid dimensions (length=0)"
    }
  ]
}

Failed orders include an error string. Completed orders include the full result (same shape as the POST /pack response).

To retry failed orders, submit a new batch with only the corrected orders.

Step 4: List all batches

curl -X GET "https://api.fractalpack.com/api/v1/batch?limit=20" \
  -H "X-Api-Key: fpk_test_your_api_key"

Response

{
  "batches": [
    {
      "batchId": "batch_x9y8z7w6",
      "status": "completed",
      "totalOrders": 500,
      "completedOrders": 497,
      "failedOrders": 3,
      "createdAt": "2026-04-03T22:00:00Z",
      "completedAt": "2026-04-03T22:05:30Z"
    },
    {
      "batchId": "batch_a1b2c3d4",
      "status": "processing",
      "totalOrders": 200,
      "completedOrders": 85,
      "failedOrders": 0,
      "createdAt": "2026-04-03T22:10:00Z",
      "completedAt": null
    }
  ],
  "nextPageToken": null,
  "hasMore": false
}

Pagination: limit (1-100, default 20) and after (cursor token).

Realistic high-volume scenario

Pack 500 orders overnight. Each order has its own item list and uses Container Master defaults (omit containers from each packRequest):

curl -X POST https://api.fractalpack.com/api/v1/batch \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: fpk_test_your_api_key" \
  -d '{
    "orders": [
      {
        "orderId": "NIGHT-RUN-0001",
        "packRequest": {
          "items": [
            { "id": "SKU-A100", "length": 10, "width": 8, "height": 4, "weight": 1.5, "quantity": 2 },
            { "id": "SKU-B200", "length": 6, "width": 6, "height": 6, "weight": 3.0, "quantity": 1 }
          ],
          "allowMultipleBoxes": true
        }
      },
      ...
    ],
    "webhookUrl": "https://hooks.example.com/nightly-batch"
  }'

When all 500 orders complete, the webhook fires with the batch ID. Pull results page by page:

# Page through completed results
curl "https://api.fractalpack.com/api/v1/batch/batch_xxx?status=completed&limit=100"
curl "https://api.fractalpack.com/api/v1/batch/batch_xxx?status=completed&limit=100&after=NIGHT-RUN-0100"

# Check failures separately
curl "https://api.fractalpack.com/api/v1/batch/batch_xxx?status=failed"

Webhook payload

When a webhookUrl is provided, the system sends an HTTPS POST when the batch completes:

{
  "event": "batch.completed",
  "batchId": "batch_x9y8z7w6",
  "status": "completed",
  "totalOrders": 500,
  "completedOrders": 497,
  "failedOrders": 3
}

The webhook URL must use HTTPS and must not target private or reserved IP ranges.

Rate limits

Batch submission is subject to rate limiting. If you exceed your plan's pack budget, the API returns 429 Too Many Requests with a Retry-After header:

HTTP/1.1 429 Too Many Requests
Retry-After: 60

Wait the specified number of seconds before retrying.

Constraints

Constraint Limit
Orders per batch 10,000
Items per order 10,000 line items
Total quantity per order 500,000 units
Containers per order 1,000 types
Webhook URL Must be HTTPS, no private IPs
Order IDs Must be unique within a batch

Error handling

Status Cause Fix
400 Empty orders array Provide at least one order
400 Duplicate orderIds Ensure all orderIds are unique
400 Invalid webhookUrl Use HTTPS, avoid private IPs
404 Batch not found Check the batchId
429 Rate limit exceeded Wait for Retry-After seconds

Next steps