Skip to Content
Welcome to Zendera Knowledge Hub
API DocumentationProduct Upsert

Product Upsert API

v1

Create, update, or delete products on existing orders with support for hierarchical relationships.

Interactive API Explorer

Loading API Documentation...

Endpoint

POST /v1/order-products/upsert

Authentication

Authorization: apikey YOUR_API_KEY_HERE

Base 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_STATUS
  • PENDING_ORDER_PRODUCT_ORDER_LOCATION_STATUS
  • COMPLETE_ORDER_PRODUCT_ORDER_LOCATION_STATUS
  • REMOVED_ORDER_PRODUCT_ORDER_LOCATION_STATUS

Product Fields

Required Fields

  • externalId: Your unique product identifier
  • externalOrderNumber: Your order identifier

Optional Fields

  • name: Product name
  • quantity: Number of items (default: 1)
  • weight: Weight in kg
  • length, width, height: Dimensions in cm
  • atomType: “colli” or “trade item” (default: “trade item”)
  • parentExternalId: Parent product’s external ID for hierarchy
  • barcodeId: Barcode for scanning
  • externalInstanceNumber: 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 failed
  • ORDER_NOT_FOUND_CODE: Order not found
  • PRODUCT_NOT_FOUND_CODE: Product to update doesn’t exist
  • DUPLICATE_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 requests

3. 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_PRODUCT for automated systems
  • Use IGNORE_IF_MODIFIED when manual changes should be preserved
Last updated on