Ship-ify API Reference
Complete guide to integrating the Ship-ify packing optimization API into your applications.
Overview
The Ship-ify API provides 3D bin packing optimization for e-commerce shipments. Given a set of available box sizes and items to ship, the API calculates the optimal packing configuration to minimize shipping costs while maximizing box utilization.
Fast Optimization
Results in milliseconds with advanced algorithms
3D Packing
True 3D bin packing with rotation support
Weight Constraints
Respects weight limits for each box type
Visualization
3D HTML visualization (Pro & Enterprise)
Authentication
All API requests require authentication using an API key. Include your API key in the request headers:
Authorization: Bearer YOUR_API_KEYImportant: Keep your API keys secure. Never expose them in client-side code or public repositories.
You can generate API keys from your dashboard.
Endpoints
/api/v1/shipping-optimizeOptimize packing for a set of items into available boxes.
Request Body
JSON object containing boxes, items, and options (see Request Format)
/api/v1/shipping-optimizeRetrieve API capabilities, usage statistics, and example requests for your tier.
Response
JSON object with tier capabilities, quota info, and usage stats
Box Sets
Box Sets allow you to save and reuse box configurations across API requests. Instead of sending the full boxes array with every request, you can reference a saved set by its unique key.
Tip: Create separate box sets for different shipping scenarios, such as standard cardboard boxes vs. insulated boxes for temperature-sensitive items.
Managing Box Sets
Create and manage your box sets from the Box Sets dashboard. Each set gets a unique key like bs_abc123xyz456.
Using Box Sets in Requests
Use boxSetKey instead of the boxes array:
{
"boxSetKey": "bs_abc123xyz456",
"items": [
{
"id": "item-001",
"name": "Product A",
"dimensions": { "length": 4, "width": 3, "height": 2 },
"weight": 1.5,
"quantity": 2
}
],
"options": {
"algorithm": "currie-fit"
}
}Box Set Limits by Tier
| Tier | Max Box Sets |
|---|---|
| Free | 3 |
| Basic | 10 |
| Pro | 50 |
| Enterprise | Unlimited |
Request Format
The POST request body must include either boxes or boxSetKey, plus items, and optionally options.
Box Object
| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Unique identifier for the box type |
| name | string | No | Human-readable name |
| dimensions | object | Yes | { length, width, height } in your preferred unit |
| weightCapacity | number | No | Box structural weight limit - max weight the box material can physically hold |
| cost | number | No | Cost per box for optimization |
Item Object
| Field | Type | Required | Description |
|---|---|---|---|
| id | string | Yes | Unique identifier for the item |
| name | string | No | Human-readable name |
| dimensions | object | Yes | { length, width, height } in your preferred unit |
| weight | number | No | Item weight for constraint checking |
| quantity | number | No | Number of this item to pack (default: 1) |
| fragile | boolean | No | Mark as fragile for special handling |
| keepUpright | boolean | No | Prevent vertical rotation |
Options Object
| Field | Type | Default | Description |
|---|---|---|---|
| algorithm | string | "currie-fit" | Packing algorithm (see Algorithms section) |
| allowRotation | boolean | true | Allow items to be rotated for better fit |
| prioritize | string | "space" | "space" | "cost" | "speed" | "consolidation" |
| enableVisualization | boolean | false | Include 3D HTML visualization (Pro+ only) |
| maxShipmentWeight | number | - | Carrier weight limit - shipments above this threshold incur overweight fees |
| oversizedItemHandling | string | "unpacked" | "custom-box" | "unpacked" - How to handle items larger than any available box |
| overweightItemHandling | string | "unpacked" | "allow" | "unpacked" - How to handle items heavier than maxShipmentWeight |
Understanding Weight Constraints
The API supports two distinct types of weight constraints:
Box Structural Limit (weightCapacity)
Set on each box type. This represents the maximum weight the box material can physically hold without breaking. The optimizer will not place items that would exceed this structural limit.
"boxes": [{ "id": "medium", "weightCapacity": 25, ... }]Carrier Shipment Limit (maxShipmentWeight)
Set in options. This represents the carrier threshold above which overweight fees apply. All shipments will be optimized to stay under this limit regardless of box capacity. When this option is set, all items must have a weight property defined.
"options": { "maxShipmentWeight": 50 }Overweight Item Handling (overweightItemHandling)
When a single item exceeds the maxShipmentWeight, this option controls how it's handled:
"unpacked"(default): Item is placed in the unpackedItems array"allow": Item is allowed to ship alone in a box, weight limit waived for this shipment
"options": { "maxShipmentWeight": 50, "overweightItemHandling": "allow" }Both constraints are enforced simultaneously. A shipment must satisfy both the box structural capacity and the carrier weight limit.
Batch Orders
Process multiple orders in a single API request. Instead of sending individual items, you can send an array of orders, each with its own items. The API will optimize packing for each order independently and return consolidated results.
Availability: Basic tier and above
Batch order processing is available for Basic, Pro, and Enterprise subscriptions with tier-based limits.
Batch Limits by Tier
| Tier | Max Orders | Max Items/Order | Max Total Items |
|---|---|---|---|
| Free | Not available | - | - |
| Basic | 5 | 10 | 50 |
| Pro | 20 | 40 | 250 |
| Enterprise | 50 | 100 | 500 |
Batch Request Format
Use the orders array instead of items. Each order must have an orderId and its own items array.
{
"boxes": [
{ "id": "small", "name": "Small Box", "dimensions": { "length": 10, "width": 8, "height": 6 }, "cost": 2.50 },
{ "id": "medium", "name": "Medium Box", "dimensions": { "length": 14, "width": 12, "height": 10 }, "cost": 4.00 }
],
"orders": [
{
"orderId": "ORD-001",
"items": [
{ "id": "item-1", "name": "Book", "dimensions": { "length": 9, "width": 6, "height": 1.5 }, "weight": 1.2 }
]
},
{
"orderId": "ORD-002",
"items": [
{ "id": "item-2", "name": "Laptop", "dimensions": { "length": 14, "width": 10, "height": 2 }, "weight": 4.5 },
{ "id": "item-3", "name": "Charger", "dimensions": { "length": 4, "width": 3, "height": 2 }, "weight": 0.3 }
]
}
],
"options": {
"algorithm": "currie-fit"
}
}Batch Response Format
The response includes results for each order plus an overall summary.
{
"success": true,
"batch": true,
"results": [
{
"orderId": "ORD-001",
"success": true,
"data": {
"shipments": [...],
"unpackedItems": [],
"summary": { "totalShipments": 1, "totalCost": 2.50, ... }
}
},
{
"orderId": "ORD-002",
"success": true,
"data": {
"shipments": [...],
"unpackedItems": [],
"summary": { "totalShipments": 1, "totalCost": 4.00, ... }
}
}
],
"summary": {
"totalOrders": 2,
"successfulOrders": 2,
"failedOrders": 0,
"totalBoxesUsed": 2,
"totalCost": 6.50,
"averageUtilization": 42.5,
"totalItemsPacked": 3,
"totalItemsUnpacked": 0
},
"metadata": {
"algorithm": "currie-fit",
"executionTime": "45ms",
"timestamp": "2025-12-06T12:00:00.000Z"
}
}Backward Compatibility
The original single-order format using items array continues to work. Batch processing is only triggered when the orders array is present.
Response Format
Successful responses include shipment details, packing statistics, and metadata.
Response Structure
| Field | Description |
|---|---|
| success | Boolean indicating request success |
| data.shipments | Array of shipment objects with packed items |
| data.unpackedItems | Items that couldn't fit in any box |
| data.summary | Aggregated statistics (total cost, utilization, etc.) |
| data.suggestions | Optimization suggestions |
| metadata | Algorithm used, execution time, tier info |
| visualizationHtml | 3D HTML visualization (Pro+ only) |
Box Structure in Shipments
Each shipment contains a box object with the following fields:
| Field | Type | Description |
|---|---|---|
| id | string | Box ID (from your submitted boxes, or "custom-*" for oversized items) |
| name | string | Box name (or "Custom Box" for oversized items) |
| dimensions | object | { length, width, height } of the box |
| cost | number | Box cost (optional, 0 for custom boxes) |
| type | string | "custom" when oversizedItemHandling is "custom-box" (only present for custom boxes) |
Packed Items Structure
Each packed item in a shipment includes the following fields:
| Field | Type | Description |
|---|---|---|
| itemId | string | Original item ID as submitted in the request |
| itemIndex | number | Index within quantity expansion (0, 1, 2, ...). For items with quantity > 1, each instance gets a unique index. |
| position | object | { x, y, z } coordinates of item placement in the box |
| rotation | object | Axis mapping showing how item was rotated to fit |
| rotatedDimensions | object | { length, width, height } after rotation applied |
Rate Limit Headers
Every response includes rate limit information:
X-RateLimit-Limit: 1000
X-RateLimit-Remaining: 985
X-RateLimit-Reset: 2025-11-30T00:00:00.000ZAlgorithms
Choose the algorithm that best fits your use case. Algorithm availability depends on your subscription tier.
first-fitAll TiersFast, simple algorithm that places items in the first available space. Best for speed-critical applications.
best-fitAll TiersFinds the best fitting space for each item, improving utilization over first-fit.
guillotineBasic+Divides space into rectangles for efficient 2D packing. Good balance of speed and utilization.
max-rectsPro+Advanced algorithm maintaining multiple free rectangles for optimal packing.
currie-fitAll Tiers (Default)Combines global box selection strategy with fast 3D placement. Uses O(items × boxes × positions) complexity for efficient packing with excellent results. Recommended for most use cases.
currie-squeezePro+Proprietary algorithm using dimensional combination analysis. Uses 2^n complexity for optimal box selection with items sorted by volume.
Subscription Tiers
| Feature | Free | Basic | Pro | Enterprise |
|---|---|---|---|---|
| Daily Requests | 100 | 1,000 | 10,000 | Unlimited |
| Max Items/Request | 10 | 25 | 100 | 1,000 |
| Max Box Types | 5 | 10 | 50 | 200 |
| 3D Visualization | - | - | ✓ | ✓ |
| Currie-Fit Algorithm | ✓ | ✓ | ✓ | ✓ |
| Currie-Squeeze Algorithm | - | - | ✓ | ✓ |
Rate Limits
Rate limits reset daily at midnight UTC. When you exceed your limit, the API returns a 429 status code.
Rate Limit Response
{
"error": "Rate limit exceeded",
"message": "You have exceeded your daily limit of 100 requests",
"limit": 100,
"remaining": 0,
"resetAt": "2025-12-01T00:00:00.000Z"
}Error Codes
| Status | Error | Description |
|---|---|---|
| 400 | Invalid request | Missing or malformed boxes/items |
| 401 | Authentication failed | Invalid or missing API key |
| 403 | Feature not available | Algorithm or feature not in your tier |
| 403 | Limit exceeded | Too many items or box types for your tier |
| 429 | Rate limit exceeded | Daily request quota exhausted |
| 500 | Internal server error | Server-side error, please retry |
Examples
Example Request
{
"boxes": [
{
"id": "b1-box",
"name": "Box B1",
"dimensions": {
"length": 7,
"width": 7,
"height": 12
},
"weightCapacity": 25,
"cost": 1.18
},
{
"id": "b3-box",
"name": "Box B3",
"dimensions": {
"length": 11,
"width": 10,
"height": 14
},
"weightCapacity": 35,
"cost": 2.11
},
{
"id": "b7-box",
"name": "Box B7",
"dimensions": {
"length": 20,
"width": 16,
"height": 18
},
"weightCapacity": 55,
"cost": 3.98
}
],
"items": [
{
"id": "BOOK-001",
"name": "Hardcover Book",
"dimensions": {
"length": 9.5,
"width": 7.5,
"height": 1.5
},
"weight": 1.8,
"quantity": 2
},
{
"id": "LAPTOP-COMP",
"name": "Laptop Computer",
"dimensions": {
"length": 18,
"width": 11,
"height": 4.5
},
"weight": 6.8,
"quantity": 1
}
],
"options": {
"algorithm": "currie-fit",
"allowRotation": true,
"prioritize": "space",
"enableVisualization": true
}
}Example Response
{
"success": true,
"data": {
"shipments": [
{
"box": {
"id": "b7-box",
"name": "Box B7",
"dimensions": {
"length": 20,
"width": 16,
"height": 18
},
"cost": 3.98
},
"packedItems": [
{
"itemId": "BOOK-001",
"itemIndex": 0,
"position": {
"x": 0,
"y": 0,
"z": 0
},
"rotation": {
"lengthAxis": "x",
"widthAxis": "y",
"heightAxis": "z"
},
"rotatedDimensions": {
"length": 9.5,
"width": 7.5,
"height": 1.5
}
},
{
"itemId": "BOOK-001",
"itemIndex": 1,
"position": {
"x": 9.5,
"y": 0,
"z": 0
},
"rotation": {
"lengthAxis": "x",
"widthAxis": "y",
"heightAxis": "z"
},
"rotatedDimensions": {
"length": 9.5,
"width": 7.5,
"height": 1.5
}
},
{
"itemId": "LAPTOP-COMP",
"itemIndex": 0,
"position": {
"x": 0,
"y": 0,
"z": 1.5
},
"rotation": {
"lengthAxis": "x",
"widthAxis": "y",
"heightAxis": "z"
},
"rotatedDimensions": {
"length": 18,
"width": 11,
"height": 4.5
}
}
],
"utilization": {
"volume": 18.2,
"weight": 18.9
},
"totalWeight": 10.4
}
],
"unpackedItems": [],
"summary": {
"totalShipments": 1,
"totalCost": 3.98,
"averageUtilization": 18.2,
"packingEfficiency": 18,
"itemsSuccessfullyPacked": 3,
"itemsUnpacked": 0
},
"suggestions": [
"Currie-Fit algorithm: Fast global box selection with efficient 3D placement"
]
},
"metadata": {
"algorithm": "currie-fit",
"executionTime": "32ms",
"timestamp": "2025-12-06T12:00:00.000Z",
"tier": "PRO"
}
}cURL Example
curl -X POST https://your-domain.com/api/v1/shipping-optimize \
-H "Authorization: Bearer YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"boxes": [
{
"id": "small-box",
"dimensions": { "length": 10, "width": 8, "height": 6 }
}
],
"items": [
{
"id": "item-1",
"dimensions": { "length": 4, "width": 3, "height": 2 }
}
]
}'