Product Upsert API
v1Create, update, or delete products on existing orders with support for hierarchical relationships.
Interactive API Explorer
Loading API Documentation...
Endpoint
POST /v1/order-products/upsertAuthentication
Authorization: apikey YOUR_API_KEY_HEREBase URLs
- Production:
https://app.zenderatms.com/api/ - Staging:
https://staging.zenderatms.com/api/
Request Structure
The API supports multiple operations in a single request:
{
"create": [
{
"externalOrderNumber": "ORDER_123",
"productRequest": {
"name": "New Pallet",
"externalId": "PALLET_NEW_001",
"quantity": 1,
"weight": 45.0,
"atomType": "colli",
"barcodeId": "NEW_PALLET_BARCODE"
}
},
{
"externalOrderNumber": "ORDER_123",
"productRequest": {
"name": "New Product",
"externalId": "PROD_NEW_001",
"quantity": 8,
"weight": 2.5,
"parentExternalId": "PALLET_NEW_001",
"atomType": "trade item"
}
}
],
"update": [
{
"externalOrderNumber": "ORDER_123",
"productRequest": {
"externalId": "PROD_001",
"quantity": 12
}
}
],
"upsert": [
{
"externalOrderNumber": "ORDER_123",
"productRequest": {
"name": "Flexible Product",
"externalId": "PROD_FLEX_001",
"quantity": 5,
"weight": 10.0
}
}
],
"updateConfig": {
"orderProducts": "REPLACE_EXISTING_ORDER_PRODUCT",
"hierarchicalMode": true
}
}Operations
Create
Creates new products on the order. Fails if product with same externalId
already exists.
Update
Updates existing products. Fails if product doesn’t exist.
Upsert
Creates product if it doesn’t exist, updates if it does exist.
Delete
Removes products from the order (specify in delete array).
Update Configuration
The updateConfig object controls how existing products are handled during
operations.
Product Update Behavior
orderProducts: Controls how existing products are updated.
Options:
"UNKNOWN_UPDATE_PRODUCT_BEHAVIOR"(default): Use system default behavior"REPLACE_EXISTING_ORDER_PRODUCT": Replace all product data with new values"IGNORE_IF_MODIFIED": Skip update if the product has been manually modified in the system
When to use each option:
- REPLACE_EXISTING_ORDER_PRODUCT: Use when you want to ensure your system data takes precedence
- IGNORE_IF_MODIFIED: Use when you want to preserve manual changes made by dispatchers/operators
Hierarchical Mode
hierarchicalMode: Boolean flag that enables special handling for parent-child
product relationships.
When hierarchicalMode: true:
- Create: Works as normal, creates products with specified parent relationships
- Update: Updates parent product and creates/updates any child products, returns error if parent is missing
- Upsert: Updates existing products or creates them if missing, including creating parent if needed
- Delete: Removes the specified product and all its child products automatically
When hierarchicalMode: false (default):
- Operations work independently on each product
- Parent-child relationships are not automatically managed
- You must handle hierarchy manually
Combined Configuration Example
{
"updateConfig": {
"orderProducts": "IGNORE_IF_MODIFIED",
"hierarchicalMode": true
}
}This configuration will:
- Skip updates to products that have been manually modified
- Automatically manage parent-child relationships
- Delete entire product trees when a parent is deleted
Product Status Control
Set product status at specific locations:
{
"externalOrderNumber": "ORDER_123",
"productRequest": {
"externalId": "PROD_001",
"orderProductLocationStatusPickup": "COMPLETE_ORDER_PRODUCT_ORDER_LOCATION_STATUS",
"orderProductLocationStatusDelivery": "PENDING_ORDER_PRODUCT_ORDER_LOCATION_STATUS"
}
}Available Status Values:
NOT_READY_ORDER_PRODUCT_LOCATION_STATUSPENDING_ORDER_PRODUCT_ORDER_LOCATION_STATUSCOMPLETE_ORDER_PRODUCT_ORDER_LOCATION_STATUSREMOVED_ORDER_PRODUCT_ORDER_LOCATION_STATUS
Product Fields
Required Fields
externalId: Your unique product identifierexternalOrderNumber: Your order identifier
Optional Fields
name: Product namequantity: Number of items (default: 1)weight: Weight in kglength,width,height: Dimensions in cmatomType: “colli” or “trade item” (default: “trade item”)parentExternalId: Parent product’s external ID for hierarchybarcodeId: Barcode for scanningexternalInstanceNumber: Unique instance identifier
Hierarchical Product Example
Creating a complete pallet structure:
{
"upsert": [
{
"externalOrderNumber": "ORDER_123",
"productRequest": {
"name": "EUR Pallet",
"externalId": "PALLET_001",
"atomType": "colli",
"quantity": 1,
"weight": 25.0,
"length": 120.0,
"width": 80.0,
"height": 180.0
}
},
{
"externalOrderNumber": "ORDER_123",
"productRequest": {
"name": "Product A",
"externalId": "PROD_A_001",
"parentExternalId": "PALLET_001",
"atomType": "trade item",
"quantity": 10,
"weight": 20.0
}
},
{
"externalOrderNumber": "ORDER_123",
"productRequest": {
"name": "Product B",
"externalId": "PROD_B_001",
"parentExternalId": "PALLET_001",
"atomType": "trade item",
"quantity": 5,
"weight": 15.0
}
}
],
"updateConfig": {
"orderProducts": "REPLACE_EXISTING_ORDER_PRODUCT",
"hierarchicalMode": true
}
}Response Structure
{
"results": {
"created": [
{
"externalId": "PALLET_NEW_001",
"orderProductId": 1001,
"status": "success"
}
],
"updated": [
{
"externalId": "PROD_001",
"orderProductId": 1002,
"status": "success"
}
],
"errors": [
{
"externalId": "INVALID_PROD_001",
"error": "INVALID_PRODUCT_CODE",
"message": "Product validation failed"
}
]
}
}Example Usage
Simple Product Update
curl -X POST "https://app.zenderatms.com/api/v1/order-products/upsert" \
-H "Authorization: apikey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"update": [
{
"externalOrderNumber": "ORDER_123",
"productRequest": {
"externalId": "PROD_001",
"quantity": 15,
"weight": 30.0
}
}
]
}'Create Hierarchical Products
curl -X POST "https://app.zenderatms.com/api/v1/order-products/upsert" \
-H "Authorization: apikey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"create": [
{
"externalOrderNumber": "ORDER_123",
"productRequest": {
"name": "New Pallet",
"externalId": "PALLET_NEW_001",
"atomType": "colli",
"quantity": 1,
"weight": 25.0
}
},
{
"externalOrderNumber": "ORDER_123",
"productRequest": {
"name": "Child Product",
"externalId": "PROD_CHILD_001",
"parentExternalId": "PALLET_NEW_001",
"atomType": "trade item",
"quantity": 8,
"weight": 16.0
}
}
],
"updateConfig": {
"hierarchicalMode": true
}
}'Product Status Management
curl -X POST "https://app.zenderatms.com/api/v1/order-products/upsert" \
-H "Authorization: apikey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"update": [
{
"externalOrderNumber": "ORDER_123",
"productRequest": {
"externalId": "PROD_001",
"orderProductLocationStatusPickup": "COMPLETE_ORDER_PRODUCT_ORDER_LOCATION_STATUS",
"orderProductLocationStatusDelivery": "PENDING_ORDER_PRODUCT_ORDER_LOCATION_STATUS"
}
}
]
}'Error Handling
Common error codes:
INVALID_PRODUCT_CODE: Product validation failedORDER_NOT_FOUND_CODE: Order not foundPRODUCT_NOT_FOUND_CODE: Product to update doesn’t existDUPLICATE_PRODUCT_CODE: Product already exists (create operation)INVALID_HIERARCHY_CODE: Invalid parent-child relationship
Best Practices
1. Use Hierarchical Mode for Complex Structures
When working with colli and trade items, enable hierarchical mode to handle parent-child relationships automatically.
2. Batch Operations
Combine multiple operations in a single request for better performance:
// Good: Single request with multiple operations
await api.upsertProducts({
create: [product1, product2],
update: [update1, update2],
delete: [delete1],
});
// Avoid: Multiple separate requests3. Handle Partial Failures
The API returns both successes and errors. Always check the response for partial failures:
const response = await api.upsertProducts(operations);
// Process successful operations
response.results.created.forEach(result => {
console.log(`Created product: ${result.externalId}`);
});
// Handle errors
response.results.errors.forEach(error => {
console.error(`Failed to process ${error.externalId}: ${error.message}`);
});4. Use Appropriate Update Behavior
Choose the right update behavior based on your workflow:
- Use
REPLACE_EXISTING_ORDER_PRODUCTfor automated systems - Use
IGNORE_IF_MODIFIEDwhen manual changes should be preserved