Split Shipments

Last updated

It’s possible to show multiple shipments in the checkout based on what is dictated by an external system.

Introduction#

This guide outlines the process of integrating the External Allocation System (EAS) with Centra's DTC API to implement split shipments. It provides detailed information on the integration flow, API specifications, and implementation steps.

In the context of this guide, EAS is a tool like an ERP, that typically acts as stock master, that can decide how to split orders based on inventory levels or other factors.

Integration Flow#

The integration of the External Allocation System with Centra's DTC API follows these main steps:

  1. Configure External Allocation Plugin: The AMS user configures the EAS API endpoint and authentication token within the External Allocation plugin in Centra.

  2. Implement EAS API Contract: Centra and the EAS communicate using a predefined API contract. This contract specifies the structure of requests sent to the EAS and the expected response format.

  3. Trigger EAS Call via DTC API: During the checkout process, a specific GraphQL mutation in the DTC API triggers the communication with the EAS. The DTC API receives and processes the response from the EAS, updating the selection's details based on the allocation results. This includes handling out-of-stock items and assigning items to delivery groups.

  4. Retrieve Delivery Groups in DTC API: Access delivery group information after order placement using the DTC API.

  5. Create Shipment out of Delivery Group in Integration API: Use the Integration API to create shipments directly from Delivery Groups.

  6. View Delivery Groups in Centra AMS: Access Delivery Groups details through Centra AMS

The following diagram illustrates the key interactions in the integration flow

split-shipment-checkout-flow

Implementation Details#

1. Configure External Allocation Plugin#

The functionality is controlled by a feature flag and requires configuration. Please contact Centra Support or your CSM in order to enable it in your Centra environment, separately in QA and Production.

The External Allocation Plugin integrates an External Allocation System into the DTC API. This plugin enables communication between the DTC API and an external system using specific API endpoint.

  1. Navigate to the External Allocation plugin settings in Centra -> System -> Stores -> [Your Store]
  2. Look for the External Allocation plugin under the Allocation option group.
  3. Configure the following settings:
    • API URL: The endpoint of your EAS REST API
    • API Secret: The authentication token for your EAS
    • API timeout limit: Maximum wait time for API response (default: 500 ms)
    • API retry amount: Number of retry attempts for failed API calls (default: 3)
    • Restrictions: Set any pricelist, market, country, or locale restrictions as needed
  4. Click Save to apply configuration

eas-plugin

With these configuration steps completed, your DTC API will be ready to communicate with your External Allocation System during the checkout process.

2. Implement EAS API Contract#

Use case: show delivery groups to the end customer in the checkout

Centra has established an API contract for the External Allocation System (EAS). It is expected that your EAS implements an API adhering to this contract. This section outlines the request and response structures, along with their descriptions and use cases.

Authorization

The EAS API implements Bearer token authentication. The token should be included in the Authorization header of each request:

1 Authorization: Bearer <your-api-token>

The API token is configured in the External Allocation Plugin settings in Centra.

Request Structure

When Centra's DTC API communicates with your EAS, it will send a POST request with the following JSON structure:

Request headers:

1 2 Authorization: Bearer <your-api-token> Content-Type: application/json

Request payload:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 { "selection": { "id": "abc123", "languageCode": "en", "currency": "USD", "lines": [ { "id": "line_id1", "productNumber": "1", "productVariantNumber": "1", "displayItemId": 60, "sizeNumber": "29", "size": "S", "ean": "1234567899", "quantity": 4 }, { "id": "line_id2", "productNumber": "2", "productVariantNumber": "2", "displayItemId": 61, "sizeNumber": "31", "size": "M", "ean": "1234567891", "quantity": 1 }, { "id": "line_id3", "productNumber": "3", "productVariantNumber": "3", "displayItemId": 61, "sizeNumber": "30", "size": "S", "ean": "1234567891", "quantity": 2 } ], "shippingAddress": { "address1": "address 1", "address2": "address 2", "zipCode": "09678", "city": "Stockholm", "state": "", "countryCode": "SE" } } }

Request Fields Description:

  • selection.id: Unique identifier for the current selection
  • selection.language: Language code for the selection
  • selection.currency: Currency code for the selection
  • selection.lines: Array of line items in the selection
    • id: Unique identifier for the line item
    • productNumber: Product identifier
    • productVariantNumber: Variant identifier
    • displayItemId: Display item identifier
    • sizeNumber: Size number
    • size: Size name
    • ean: EAN/barcode for the product
    • quantity: Requested quantity
  • selection.shippingAddress: Shipping address details for the order

Response Structure

Your EAS should process the request and return a response with the following JSON structure:

Response payload - 200 OK

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 { "selectionId": "abc123", "attributes": [ { "type": "ingrid-cart", "name": "siteId", "value": "S400" }, { "type": "ingrid-cart", "name": "marketId", "value": "M400" } ], "lines": [ { "id": "line_id1", "availability": "partially_in_stock", "requestedQuantity": 4, "availableQuantity": 3 }, { "id": "line_id2", "availability": "in_stock", "requestedQuantity": 1, "availableQuantity": 1 }, { "id": "line_id3", "availability": "out_of_stock", "requestedQuantity": 2, "availableQuantity": 0 } ], "deliveryGroups": [ { "id": "DeliveryGroup1", "warehouseId": 1, "name": "Standard Delivery", "lines": [ { "id": "line_id1", "quantity": 2 // Only 2 available for shipping } ], "attributes": [ { "type": "ingrid-delivery-group", "key": "warehouseId", "value": "W194" } ] }, { "id": "DeliveryGroup2", "warehouseId": 2, "name": "Express Delivery", "lines": [ { "id": "line_id1", "quantity": 1 // Only 1 available for shipping }, { "type": "ingrid", "id": "line_id2", "quantity": 1 } ], "attributes": [ { "type": "ingrid-delivery-group", "key": "warehouseId", "value": "W195" } ] } ] }

Response Fields Description:

  • selectionId: The ID of the selection being processed
  • attributes: Additional attributes for the cart (e.g., site ID, market ID)
    • type: The type of the attribute (“ingrid-cart“)
      • ingrid-cart: Attributes of this type will be passed directly to Ingrid cart attributes. These are used for integration with the Ingrid delivery checkout
    • key: The name of the attribute (e.g., “siteId“, “marketId“)
    • value: The value of the attribute
  • lines: Array of updated line items
    • id: Line item identifier
    • availability: Stock status ("in_stock", "partially_in_stock", or "out_of_stock")
    • requestedQuantity: Original requested quantity
    • availableQuantity: Actually available quantity
  • deliveryGroups: Array of delivery groups for split shipments
    • id: Unique identifier for the delivery group
    • warehouseId: Identifier of the warehouse for this group
    • name: Name of the delivery group
    • lines: Array of line items in this delivery group
      • id: Line item identifier
      • quantity: Quantity allocated to this delivery group
    • attributes: Additional attributes for the delivery group
      • type: The type of the attribute (“ingrid-delivery-group“)
        • ingrid-delivery-group: Attributes of this type will be passed to Ingrid delivery group attributes. These are used for integration with the Ingrid delivery checkout
      • key: The name of the attribute (e.g., “warehouseId“)
      • value: The value of the attribute

3. Trigger API call to EAS in DTC API#

Use case: frontend decides when to ask an external allocation system about potentially splitting the order into multiple deliveries. You may want to do so earlier or later in the checkout depending on your unique customer journey and optimisation needs.

To initiate the External Allocation System (EAS) process during checkout, the DTC API provides a specific GraphQL mutation. The mutation is defined as follows:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 mutation TriggerSelectionAction { triggerSelectionAction(triggerEngine: [EXTERNAL_ALLOCATION]) { selection { id # Other relevant selection fields } userErrors { message code ... on UnavailableItem { message path originalQuantity unavailableQuantity availableQuantity item { id } displayItem { id } } } } }

How to use this mutation for EAS check:

  1. Input: The triggerEngine parameter is set to [EXTERNAL_ALLOCATION] to specifically trigger the EAS process.
  2. Response:
    • selection: Returns the updated selection object after EAS processing
    • userErrors: Contains any errors that occurred during the process

EAS Response Processing

After receiving the response from the EAS, the DTC API processes it in the following manner:

  1. Availability Update:

    • Full Availability:
      • If all items are available, the selection remains unchanged.
    • Partial Availability:
      • If lines are partially in stock, the amount that cannot be fulfilled is removed from the selection.
      • The mutation returns userErrors with UnavailableItem information. Example of userErrors for partially removed item:
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 "userErrors": [ { "message": "item 1-1 was partially removed due to limited availability", "path": ["triggerSelectionAction", "selection", "lines", "0"], "originalQuantity": 5, "unavailableQuantity": 3, "availableQuantity": 2, "item": { "id": "1-1" }, "displayItem": { "id": 1 } } ]
    • Out of stock:
      • Lines that are out of stock are removed from the selection entirely.
      • The mutation returns userErrors with UnavailableItem information. Example of a completely removed item:
    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 "userErrors": [ { "message": "item 1-1 was removed due to unavailability", "path": ["triggerSelectionAction", "selection", "lines", "0"], "originalQuantity": 5, "unavailableQuantity": 5, "availableQuantity": 0, "item": { "id": "1-1" }, "displayItem": { "id": 1 } } ]
  2. Delivery Group Handling:
    The DTC API sets the received delivery groups on the selection.

  3. Ingrid Integration:

    • After updating the selection, the DTC API passes the delivery group information, including associated attributes, to Ingrid.
    • This information includes:
      • The structure of delivery groups
      • Items allocated to each delivery group
      • Warehouse associations for each delivery group
      • "ingrid-cart" attributes for cart-level information
      • "ingrid-delivery-group" attributes for specific delivery group details
    • Ingrid uses this received data to represent the split shipment options in its widget.
    • The Ingrid widget then displays accurate delivery choices to the customer, reflecting the allocation decisions made by the EAS.
  4. Error Handling:

    • If the EAS response indicates any errors or inconsistencies, the DTC API handles these according to predefined rules.
    • This may include retrying the allocation request, falling back to default allocation logic, or presenting an error message to the user.
  5. Selection Update:

    • The DTC API updates the current selection with all the processed information, including updated item quantities, delivery groups, and any relevant attributes.
  6. Checkout Flow Continuation:

    • The customer can now see and select from accurate delivery options that reflect the split shipment possibilities determined by the EAS.

This process ensures that the allocation information provided by the EAS is correctly integrated into the DTC API and accurately represented to the customer through the Ingrid widget, enabling proper split shipment handling and delivery option selection.

Error handling

  1. EAS Unavailability:

    • If the EAS is unavailable (e.g., wrong API URL), the system implements retry logic based on the configured settings.
    • If all retry attempts fail:
      • The selection remains unchanged.
      • An appropriate error message is logged.
      • No user errors are returned to avoid confusing the end-user.
  2. EAS Response Timeout:

    • The system enforces a timeout limit for EAS responses, which is configurable in the External Allocation Plugin.
    • If the EAS response exceeds this timeout, it's treated as a failed request and triggers the retry logic.
  3. Delivery Group Data Inconsistency:

    • The system validates the consistency of delivery group data from the EAS.
    • Inconsistencies are detected when:
      • The quantity of an item in delivery groups exceeds the original selection quantity.
      • A delivery group contains an item not present in the original selection.
      • The total quantity of an item across all delivery groups doesn't match the original selection quantity.
    • If inconsistencies are detected:
      • The selection remains unchanged.
      • An appropriate error message is logged.
      • No changes are applied to the selection.
  4. Retry Logic:

    • Applies to both EAS unavailability and response timeout scenarios.
    • The number of retry attempts and the delay between retries are configurable in the External Allocation Plugin.
    • For each retry attempt:
      • If successful, the response is processed normally.
      • If it results in another error, the next retry is attempted (if available).
    • If all retry attempts fail:
      • The selection remains unchanged.
      • An appropriate error message is logged.
      • No user errors are returned to the frontend.

Checkout flow after calling mutation triggerSelectionAction

After successfully calling mutation triggerSelectionAction(triggerEngine: [EXTERNAL_ALLOCATION]):

  1. The DTC API will have communicated with the EAS and updated the selection with allocation results.
  2. The updated selection will reflect any changes in item availability or delivery group assignments in Ingrid widget.
  3. The Ingrid widget will be updated to reflect the delivery groups that were set based on the data provided by the EAS.

4. Retrieve Delivery Groups in DTC API#

Use case: build an order confirmation page that appears to the customer after they’ve paid for the order and displays delivery groups they saw in the checkout along with associated delivery methods and costs. You may also use the retrieved delivery group ids to later create shipments with their help.

As part of implementing Split Shipments, the DTC API has been enhanced to support the concept of Delivery Groups within the Order type, so it’s possible to retrieve delivery groups information after order placement.

DeliveryGroup Schema

The DTC API includes a DeliveryGroup type with the following structure:

1 2 3 4 5 6 7 8 type DeliveryGroup { id: String! name: String shippingMethod: ShippingMethod! shippingPrice: MonetaryValue! lines: [DeliveryGroupLine!]! attributes: [Attribute!]! }
  • id: A unique identifier for each delivery group.
  • name: The human-readable name of the delivery group.
  • shippingMethod: Specifies the Centra shipping method for the items within this group. Note that this is different from the Ingrid-specific shipping method.
  • shippingPrice: The cost associated with shipping the items in this group.
  • lines: A collection of delivery group lines associated with this Delivery Group. Each GroupLine includes details about the item and its quantity within the group.
  • attributes: Custom attributes associated with the delivery group.

You may notice there are 2 shipping costs associated with each delivery group:

  • deliveryGroup.shippingMethod.price: This is the current price of this shipping method configured in Centra. It can be changed by Centra admins. It will always return the current cost of this shipping method, NOT the shipping cost at the moment of order placement.
  • deliveryGroup.shippingPrice: Actual shipping cost applied to this delivery group, recorded upon order creation. Might differ from configured shippingMethod.price described above, if for example a free-shipping voucher was used with this order, or if Ingrid shipping provider is used
1 2 3 4 type DeliveryGroupLine { quantity: Int! line: Line! }
  • quantity: Delivery Group Line original quantity - cancelled quantity
  • line: line associated with the Delivery Group Line.
1 2 3 4 type Order { # ... other fields deliveryGroups: [DeliveryGroup!]! }

Retrieving Delivery Information

After an order has been placed, you can retrieve the order information, including delivery groups, using the DTC API. This can be done through the receipt query Here's an example of how to query for this information:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 query { receipt { order { id status number orderDate deliveryGroups { id name shippingMethod { id name } shippingPrice { value currency } lines { quantity line { id item { id name } } } } } } }

Using the Retrieved Data

With this data, you can:

  1. Display a detailed order confirmation, including split shipment information.
  2. Show the breakdown of items in each delivery group.
  3. Show shipping method and price information for each delivery group.

5. Retrieve Delivery Groups in Integration API#

The Order type in the Integration API has been extended to include Delivery Groups:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 type Order { # ... existing fields deliveryGroups: [DeliveryGroup!]! } type DeliveryGroup { id: String! name: String shippingMethod: ShippingMethod! shippingPrice: MonetaryValue! lines: [DeliveryGroupLine!]! attributes: [Attribute!]! } type DeliveryGroupLine { quantity: Int! line: OrderLine! }

This structure allows you to access Delivery Group information when querying orders through the Integration API.

6. Create Shipment out of Delivery Groups in Integration API#

Creating Shipments from Delivery Groups

Use case: create shipments out of delivery group ids without having to specify each line item that belongs to the delivery group in the create shipment request.

The Integration API now supports creating shipments directly from Delivery Groups. This is achieved through updates to the ShipmentCreateInput:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 input ShipmentCreateInput { order: OrderInput! """ Lines to be included in the shipment. Note: This field should be omitted if deliveryGroup is provided. If using deliveryGroup, lines from the DeliveryGroup will be used. """ lines: [ShipmentLineInput!] """ Input for providing id of the delivery group to create a shipment from. If deliveryGroup is provided, the lines field will be ignored and delivery group lines will be used. A Delivery Group is a subset of an order to be shipped together from the same location. Used in split shipments scenarios, each group can have its own shipping method, cost, and estimated delivery time. """ deliveryGroup: DeliveryGroupInput # ... other fields } input DeliveryGroupInput { id: Int! }

Usage

When creating a shipment, you can now choose to either:

  1. Specify individual lines using the lines field, or
  2. Provide a deliveryGroup to automatically include all lines from that group.

If both lines and deliveryGroup are provided, the deliveryGroup takes precedence and the lines input field will be ignored.

Example mutation to create a shipment using a Delivery Group:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 mutation CreateShipment { shipmentCreate(input: { order: { id: "123" } deliveryGroup: { id: 456 } # other shipment details... }) { shipment { id # other shipment fields... } userErrors { message code } } }

7. Cancel an order line in Integration API#

Cancelling the order line

The Integration API mutation cancel has been updated to reflect the cancelled order line quantity on the relevant delivery group lines (one order line can be split into several delivery group lines). The delivery group lines affected are selected internally, but you can prioritize the delivery group to be cancelled by using a new optional field, deliveryGroupId, in the mutation:

1 2 3 4 5 6 input OrderLineCancelInput { line: OrderLineInput! quantity: Int! stockActionPolicy: StockPolicyActionInput! = {removeItemsFromStock: true} deliveryGroupId: Int }

Effects on shipment creation

When creating a shipment via deliveryGroup, it will take into consideration the cancelled lines.

Effects on API responses

We will observe 3 effects on 2 APIs:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 # Integration API type DeliveryGroupLine { "The current quantity for the delivery group line, excluding cancelled units" quantity: Int! cancelledQuantity: Int! orderLine: OrderLine! } # DTC API type DeliveryGroupLine { quantity: Int! line: Line! }
  • On Integration API DeliveryGroupLine, cancelledQuantity will change
  • On Integration API DeliveryGroupLine, quantity will change as it returns originalQuantity - cancelledQuantity
  • On DTC API DeliveryGroupLine, quantity will change as it returns originalQuantity - cancelledQuantity

8. View Delivery Groups information in Centra AMS#

The Centra AMS has been updated to display Delivery Group information, providing administrators with a clear view of split shipments and their details.

Customer Info Section

In the Order -> Customer Info -> Other information section, multiple Ingrid delivery group attributes are now displayed.

split-shipment-delivery-groups-ams

Delivery Information#

  1. General Ingrid Information:
    • Ingrid V2 ID
    • Ingrid V2 Door Code
    • Ingrid Courier Instructions
    • Ingrid V2 Cart Attributes
  2. Delivery Group Specific Information:
    • Ingrid V2 Service Method
    • Ingrid V2 Converted Method ID
    • Ingrid V2 Pickup
    • Ingrid V2 Delivery Time
    • Ingrid V2 TOS ID

Ordered Products Section#

In the AMS Orders -> Order view, the Ordered Products section now displays a detailed breakdown of items grouped by delivery groups.

split-shipment-order-view-ams