Last updated

Ingrid Shipping Adapter

Overview

The Ingrid Adapter integrates Ingrid Delivery Checkout with Norce Checkout. It enables merchants to offer dynamic shipping options including home delivery, pickup points, and scheduled delivery windows directly within their checkout flow. Changes made in Norce Checkout are synced with Ingrid and vice versa. Read more on Ingrid Developer Documentation.

Environments

There are three environments that you can use. Replace {slug} with your merchant slug.

EnvironmentAddress
Playgroundhttps://{slug}.api-se.playground.norce.tech/checkout/ingrid-adapter
Stagehttps://{slug}.api-se.stage.norce.tech/checkout/ingrid-adapter
Productionhttps://{slug}.api-se.norce.tech/checkout/ingrid-adapter

Getting Started as a Partner

To use the Ingrid Shipping adapter, you need to set up your Ingrid account and configure the adapter in Norce Checkout Admin.

Prerequisites

Before configuring the adapter, ensure you have the following from Ingrid:

  1. API Key: Obtain your API key from your Ingrid account
  2. API URL: The Ingrid API endpoint for your environment (staging or production)

Ingrid API Environments

EnvironmentIngrid API URL
Productionhttps://api.ingrid.com
Staginghttps://api-stage.ingrid.com

Configuration

Add your configuration for the Ingrid Shipping adapter in Norce Checkout Admin. The configuration requires:

FieldDescriptionExample Value
apiSettings.apiKeyYour Ingrid API keyyour-api-key
apiSettings.apiUrlIngrid API URLhttps://api-stage.ingrid.com
adapter.internalUrlInternal URL for backend callbackshttps://ingrid-adapter.checkout.playground.internal.norce.tech
adapter.publicUrlPublic URL for client-side requestshttps://{slug}.api-se.playground.norce.tech/checkout/ingrid-adapter

Optional Configuration

FieldDescriptionDefault
options.useAddressFormUse Ingrid's integrated address form instead of search address mode. When enabled, Ingrid handles address collection and customer data flows from Ingrid to Norce.false
options.useMinimalSearchAddressOnly send country and postal code to Ingrid. Useful when full address validation causes issues.false
options.externalIdSourceOrder property used as Ingrid's external ID. Options: OrderId or OrderCartReference.OrderId
options.deliveryGroupHeaderTemplateTemplate for delivery group headers sent to Ingrid; {0} is replaced with the 1-based group numberDelivery {0}

Example Configuration

{
  "$schema": "https://checkout-configuration.norce.tech/schemas/ingrid_adapter.json",
  "id": "ingrid_adapter",
  "active": true,
  "adapter": {
    "internalUrl": "https://ingrid-adapter.checkout.playground.internal.norce.tech",
    "publicUrl": "https://{slug}.api-se.playground.norce.tech/checkout/ingrid-adapter"
  },
  "apiSettings": {
    "apiKey": "your-ingrid-api-key",
    "apiUrl": "https://api-stage.ingrid.com"
  },
  "options": {
    "useAddressForm": false,
    "useMinimalSearchAddress": false,
    "externalIdSource": "OrderId",
    "deliveryGroupHeaderTemplate": "Delivery {0}"
  }
}

Create Shipping

To get an Ingrid Delivery Checkout session with shipping options, create a shipping using the Ingrid adapter.

POST /api/checkout/v1/orders/{order_id}/shippings
Host: {slug}.api-se.stage.norce.tech
x-merchant: {merchant}
x-channel: {channel}
Authorization: Bearer {token}

The Ingrid adapter will fetch the order, map it to Ingrid's format, and create a session. The response contains the Norce shipping ID, the Ingrid session ID, and an HTML snippet for embedding the widget.

{
  "shippingId": "sGMVlgVNMjCDxsdJaOwmklGEpjM",
  "htmlSnippet": "<div id=\"shipwallet-container\">...</div>",
  "sessionId": "VM2-a1bc234...",
  "useAddressForm": false
}
Automatic Hook Registration

The adapter will register any hooks and notifications required to keep track of changes to the order, so you will not need to inform it of changes made to the order by other adapters.

Using the Response with the Ingrid Widget

The response contains an htmlSnippet that includes the Ingrid widget initialization script and container. Insert this snippet into your checkout page where you want the delivery options to appear.

<!-- Widget container - insert the htmlSnippet here -->
<div id="shipwallet-container">
  <!-- The htmlSnippet from the API response goes here -->
</div>

For detailed widget integration instructions, see the Ingrid Frontend Integration documentation.

<!-- Example: Embedding the Ingrid widget -->
<script>
// After calling the Create Shipping endpoint and receiving the response:
const response = /* response from POST /api/checkout/v1/orders/{order_id}/shippings */;
const orderId = /* your order ID */;
const shippingId = response.shippingId;
const merchant = /* your merchant ID */;
const channel = /* your channel ID */;

// Insert the HTML snippet into your page
document.getElementById('shipwallet-container').innerHTML = response.htmlSnippet;

// Initialize the Ingrid event listener
window._sw = window._sw || function() { (window._sw.q = window._sw.q || []).push(arguments); };

// Listen for shipping option changes
_sw('on', 'shipping_option_changed', async function(data) {
  // Call the shipping-changed endpoint to update Norce
  await fetch(`/api/checkout/v1/callback/orders/${orderId}/shippings/${shippingId}/shipping-changed`, {
    method: 'POST',
    headers: {
      'x-merchant': merchant,
      'x-channel': channel,
      'Authorization': 'Bearer ' + token
    }
  });
});

// Only needed when using address form mode (useAddressForm: true)
_sw('on', 'address_changed', async function(data) {
  await fetch(`/api/checkout/v1/callback/orders/${orderId}/shippings/${shippingId}/customer-changed`, {
    method: 'POST',
    headers: {
      'x-merchant': merchant,
      'x-channel': channel,
      'Authorization': 'Bearer ' + token
    }
  });
});
</script>

Get Shipping Session

To retrieve an existing Ingrid session with the latest shipping data, use the GET endpoint:

GET /api/checkout/v1/orders/{order_id}/shippings/{shipping_id}
Host: {slug}.api-se.stage.norce.tech
x-merchant: {merchant}
x-channel: {channel}
Authorization: Bearer {token}

This returns the same structure as the create endpoint, allowing you to re-render the widget if needed.

Client-Side Callbacks

Required Client-Side Callbacks

Ingrid will not inform the adapter directly of all changes made through the Ingrid widget. When a user interacts with the widget (selects a shipping option or enters address information), the widget triggers events. You need to listen for these events and call the Norce Ingrid Adapter API to update the order.

For more details, see the Ingrid Frontend Integration documentation.

Listening to Ingrid Events

The Ingrid widget uses a global _sw function to register event listeners. Set up your listeners after the widget is loaded:

// Initialize the Ingrid event listener
window._sw = window._sw || function() { (window._sw.q = window._sw.q || []).push(arguments); };

// Called when customer selects a shipping option
_sw('on', 'shipping_option_changed', async function(data) {
  await fetch(`/api/checkout/v1/callback/orders/${orderId}/shippings/${shippingId}/shipping-changed`, {
    method: 'POST',
    headers: {
      'x-merchant': merchant,
      'x-channel': channel,
      'Authorization': 'Bearer ' + token
    }
  });
});
No Request Body Required

The shipping-changed and customer-changed endpoints do not require a request body. The adapter fetches the current session state directly from Ingrid when called.

Shipping Changed

When the shipping_option_changed event is triggered, call the shipping changed endpoint to update the Norce order with the user's selection:

POST /api/checkout/v1/callback/orders/{order_id}/shippings/{shipping_id}/shipping-changed
Host: {slug}.api-se.stage.norce.tech
x-merchant: {merchant}
x-channel: {channel}
Authorization: Bearer {token}

Customer Changed (Address Form Mode Only)

When using address form mode (useAddressForm: true), listen for the address_changed event and call the customer changed endpoint to sync address data from Ingrid to Norce:

POST /api/checkout/v1/callback/orders/{order_id}/shippings/{shipping_id}/customer-changed
Host: {slug}.api-se.stage.norce.tech
x-merchant: {merchant}
x-channel: {channel}
Authorization: Bearer {token}

Automatic Updates

Automatic Background Updates

The adapter automatically handles updates when the Norce order changes. These hooks are registered automatically when creating the session, so no action is required from the partner.

Cart Changed

When items in the cart change, the adapter receives a callback and updates the Ingrid session with the new cart data. This ensures that shipping prices and availability are always accurate based on the current cart contents. Cart changes replace the entire Norce Checkout cart, which clears the delivery group indices used for split shipment, so an API consumer that uses split shipment must re-apply them with its own hook. See Required Cart Hook for Ingrid Split Shipment.

Customer Changed (Search Address Mode)

When customer address changes in Norce and the adapter is configured with useAddressForm: false (the default), the adapter automatically updates Ingrid with the new address. This hook is not registered when using address form mode, as customer data flows from Ingrid to Norce instead.

State Changed

When the order state changes, the adapter reacts accordingly:

  • Processing: Validates the Ingrid session to ensure it's ready for completion
  • Accepted: Completes the Ingrid session, finalizing the delivery selection

Completing the Session

As you complete your order (usually driven by a payment adapter), the Ingrid adapter will react to the state change and complete the session in Ingrid. The shipping object will then contain the Ingrid delivery reference (tos_id) in the tmsReference field.

Widget Integration

The Ingrid Delivery Checkout widget is embedded in your frontend using the htmlSnippet returned from the adapter. The widget provides a user interface for selecting shipping options, pickup points, and delivery time windows.

For detailed widget integration instructions, see the Ingrid Frontend Integration documentation.

Integration Modes

The adapter supports two integration modes controlled by the useAddressForm configuration option:

Search Address Mode (default): Customer address from the Norce order is sent to Ingrid. Delivery options are displayed based on the provided address. Address changes in Norce are automatically synced to Ingrid via backend hooks.

Address Form Mode: Ingrid's integrated address form handles address collection. Customer information flows from Ingrid back to the Norce order via the client-side customer-changed callback.

Promotions and Discounts

The Ingrid Adapter handles two types of discounts: item-level discounts (reflected in per-item pricing) and shipping discounts (forwarded to Ingrid as voucher codes). Promotions flow one way — from Norce to Ingrid. No promotion data is mapped back from Ingrid to Norce.

Setup Requirements

For shipping discount vouchers to work end-to-end, both Norce Commerce and Ingrid must be configured with matching rules:

In Norce Commerce:

  1. Create a promotion in Norce Commerce Admin using the "Discount freight" effect type (the effect type that targets shipping costs rather than item prices).
  2. Assign a discount code (voucher code) to the promotion.
  3. Optionally configure promotion attributes (such as freightDiscountPct).

The Norce Adapter automatically classifies promotions with the "Discount freight" effect as type = shipping on the Norce Checkout order. All other promotions are classified as type = item.

In Ingrid:

  1. Configure a shipping rule in Ingrid that matches the same voucher code used in Norce Commerce (e.g., a free shipping rule triggered by the code freefreight).
  2. Coordinate with your Ingrid account manager to ensure matching voucher rules are set up.
Both Systems Must Match

The voucher codes sent to Ingrid must match rules configured on the Ingrid side. If Ingrid does not have a matching rule for a given voucher code, the code is ignored and no shipping discount is applied.

How Discounts Are Mapped (Norce → Ingrid)

When the Ingrid Adapter creates or updates a session, it maps discounts as follows:

WhatHow
Item discount per line(originalTotal.includingVat − total.includingVat) × 100 → cart.items[].discount
Item undiscounted priceprice.includingVat × 100 → cart.items[].price
Shipping discount codescart.discounts[type=shipping].code → cart.vouchers
Shipping discount attributesdiscount.attributes → cart.attributes (flattened as key=value)
Cart total (post-discount)cart.total.includingVat × 100 → cart.total_value
Cart total discountNot set by the adapter — cart.total_discount defaults to 0

Item-level discounts (type = item) are not forwarded as vouchers — their effect is already captured in the per-item discount field. Only shipping discounts produce voucher entries.

When the Ingrid session is mapped back to Norce, no promotion data is extracted. The entire Ingrid session is serialized as raw JSON into the shippingData attribute on the Norce shipping object.

Example

Norce Checkout order with a shipping discount:

{
  "cart": {
    "discounts": [
      {
        "type": "shipping",
        "name": "free freight",
        "code": "freefreight",
        "attributes": { "code": "free_freight" }
      }
    ],
    "items": [
      { "sku": "PROD-001", "quantity": 1, "price": { "includingVat": 1295.00 }, "total": { "includingVat": 1295.00 }, "originalTotal": { "includingVat": 1295.00 } },
      { "sku": "PROD-002", "quantity": 1, "price": { "includingVat": 299.00 }, "total": { "includingVat": 299.00 }, "originalTotal": { "includingVat": 299.00 } }
    ],
    "total": { "includingVat": 1594.00 }
  }
}

Resulting Ingrid session request:

{
  "cart": {
    "vouchers": ["freefreight"],
    "attributes": ["code=free_freight", "b2c"],
    "total_value": 159400,
    "items": [
      { "sku": "PROD-001", "discount": 0, "price": 129500, "quantity": 1 },
      { "sku": "PROD-002", "discount": 0, "price": 29900, "quantity": 1 }
    ]
  }
}

The shipping discount code "freefreight" is sent as a voucher. The discount attribute "code": "free_freight" is flattened to "code=free_freight" in the cart attributes. Item discounts are 0 because each item's originalTotal equals its total. If multiple shipping discounts are applied, all codes are collected into the cart.vouchers list.

Split Shipment

Split shipment in the Ingrid Shipping Adapter means that a single Ingrid Delivery Checkout session is split into multiple deliveries — called delivery groups — where each group can have its own carrier, shipping option, pickup location, and price. Split shipment is used when items in the same Norce Checkout cart cannot ship together, for example when they come from different warehouses or suppliers, or when only some items are in stock. The customer selects a delivery option per group in the Ingrid widget, and the Norce Checkout shipping object receives one delivery entry per group.

Using split shipment with the Ingrid Shipping Adapter has two parts, and both are the responsibility of the API consumer:

  1. Assigning items to delivery groups — set cart.items[].logistics.delivery.group on the Norce Checkout order.
  2. Keeping the group assignments alive — the group values are wiped every time the cart changes, so the API consumer must register a Norce Checkout hook that re-applies them. Without that hook, split shipment appears to work until the customer changes the cart, and then silently collapses back into a single delivery.

Assigning Cart Items to Ingrid Delivery Groups

Splitting in the Ingrid Shipping Adapter is driven entirely by the logistics.delivery.group index on each item in the Norce Checkout cart. Items that share the same group index belong to the same shipment. The Ingrid Adapter groups the cart items by this index and sends one Ingrid cart group per index. The field exists in both the V0 and the V1 Norce Checkout Order API, and a missing or null value is treated as group 0.

{
  "id": "order-123",
  "cart": {
    "items": [
      {
        "sku": "PROD-001",
        "quantity": 1,
        "logistics": { "delivery": { "group": 0 } }
      },
      {
        "sku": "PROD-002",
        "quantity": 2,
        "logistics": { "delivery": { "group": 1 } }
      }
    ]
  }
}
The API Consumer Owns the Splitting Ruleset

The Ingrid Adapter does not define or enforce any logic for splitting the cart. Instead, the API consumer is responsible for assigning the logistics.delivery.group index on each Norce Checkout cart item based on its own business rules (for example per warehouse, per supplier, or per availability date). The adapter only forwards the grouping it receives.

Ingrid Delivery Group Rules and Constraints

The following rules apply to logistics.delivery.group when the Ingrid Shipping Adapter maps a Norce Checkout cart to an Ingrid session:

  • Default behavior (single shipment): If every cart item has group index 0 — the default when no group is set — no groups are sent to Ingrid and the order is treated as a single shipment.
  • Sequential indices required: Group indices must be sequential, start at 0, and contain no gaps (for example 0,1,2). A gap, such as items in groups 0 and 2 with no item in group 1, causes a validation error with error code ingrid-delivery-group-gap (ErrorCode.Ingrid.DeliveryGroupGap) and the message Delivery group indices must be sequential without gaps. Because the Ingrid Adapter runs inside the hook chain of the cart change, this validation error fails the entire cart change and rolls it back. An API consumer that assigns delivery groups must therefore renumber the remaining groups when an item is removed.
  • Groups are per cart item line: The group is assigned per cart item line, not per unit. The quantity of a single cart item line cannot be spread across two delivery groups. To ship two units of the same SKU in different groups, use two separate cart item lines.
  • Group headers: Each group is sent to Ingrid as a cart group with a header. The header text is controlled by the optional configuration field options.deliveryGroupHeaderTemplate, which defaults to "Delivery {0}", where {0} is replaced with the 1-based group number. With the default template, groups are labelled "Delivery 1", "Delivery 2", and so on.
  • Group ids: Group ids sent to Ingrid are generated as {orderId}-group-{index}, using the zero-based group index (for example order-123-group-0).

Required Cart Hook for Ingrid Split Shipment

Delivery group assignments do not survive a cart change in Norce Checkout. To use split shipment with the Ingrid Shipping Adapter, the API consumer must register a hook that re-applies the delivery groups on every cart change.

Why the delivery group values are lost: The Norce Commerce basket has no concept of delivery groups. On every cart change — quantity update, added or removed item, discount code, price recalculation, or basket webhook — the Norce Commerce Adapter rebuilds the cart from the basket and replaces the entire cart on the Norce Checkout order. The cart model of the Norce Commerce Adapter has no delivery property, so the cart it sends never contains logistics.delivery, and the Norce Checkout Order API applies the update as a full replace of /cart without merging previous values. The result is that all logistics.delivery.group values are reset to null (which means group 0) on every cart change.

Split Shipment Requires a Cart Hook

There is no built-in mechanism in Norce Checkout or in the Ingrid Shipping Adapter that preserves logistics.delivery.group across cart changes. An API consumer that uses split shipment must register a hook that re-assigns the delivery group indices on every cart change. Without it, an order that started as a split shipment collapses into a single delivery as soon as the cart changes.

Registering the hook: Register the hook once per order, typically directly after creating the order. For a general introduction to hooks in Norce Checkout, see Hooks.

POST /api/v1/checkout/orders/{orderId}/hooks
Host: {slug}.api-se.{environment}.norce.tech/checkout/order
x-merchant: {merchant}
x-channel: {channel}
Authorization: Bearer {token}
Content-Type: application/json

{
  "adapterId": "{your-adapter-or-integration-id}",
  "reference": "assign-delivery-groups",
  "description": "Re-assigns Ingrid delivery group indices on cart changes",
  "scope": "/cart",
  "target": "/cart",
  "invoke": "https://your-service.example.com/hooks/orders/{order_id}/assign-delivery-groups",
  "version": "v1"
}
  • scope is the path in the order the hook subscribes to. /cart means the hook is invoked whenever the cart changes.
  • target is the part of the order the hook is allowed to patch. Patch operations outside the target path are rejected by the Norce Checkout Order API.
  • invoke is the endpoint of the API consumer. The Norce Checkout Order API sends the full order as the request body and expects a JSON Patch document in the response. The substring {order_id} in the URL is replaced with the id of the order before the call is made.
  • reference is a stable identifier for the hook across orders, used to track the hook in the event log, and description documents its purpose.
  • version is the version of the order body the hook receives. Use v1 to receive the V1 order model.

Hook contract: On every cart change, the endpoint receives the full Norce Checkout order and must respond with HTTP 200 and a JSON Patch document (RFC 6902) that sets the delivery group of each cart item. Respond with an empty array [] when nothing needs to change.

[
  { "op": "add", "path": "/cart/items/0/logistics/delivery", "value": { "group": 0 } },
  { "op": "add", "path": "/cart/items/1/logistics/delivery", "value": { "group": 1 } },
  { "op": "add", "path": "/cart/items/2/logistics/delivery", "value": { "group": 0 } }
]

Rules for implementing the delivery group hook:

  • Patch the delivery object, not the group field. After a cart change, the cart item usually has no delivery object at all, and a patch operation whose parent path is missing is rejected with For operation 'add', the target location specified by path '/cart/items/0/logistics/delivery/group' was not found., which fails the whole cart change. Patching /cart/items/{index}/logistics/delivery with a value such as { "group": 1 } both creates and overwrites the delivery object and keeps the other logistics fields on the item. If a cart item has no logistics object either, patch /cart/items/{index}/logistics instead, and include the item's existing logistics fields from the request body in the value, otherwise they are lost.
  • Patch only the delivery data. Do not respond with a patch that replaces the whole cart or whole cart items. If the full order is deserialized into a consumer-side model and echoed back, any field the model does not know about is silently dropped, and value precision (for example on decimals) can be lost.
  • Keep the group indices contiguous. If the customer removes the last item of group 1 while group 2 still has items, the hook must renumber group 2 to 1. Otherwise the Ingrid Adapter rejects the cart with ingrid-delivery-group-gap and the entire cart change fails and is rolled back.
  • Do not call the Norce Checkout Order API from inside the hook. Mutating the order from inside a hook starts a second hook chain that races the current one. Returning patch operations is the only safe way to write during a hook.
  • Use the order from the request body, not a fresh GET on the order. A GET during the hook chain returns the state from before the ongoing change.
  • Be fast and reliable. The hook is synchronous within the checkout flow. A non-2xx response blocks the cart change and triggers a best-effort rollback of the hooks that were already invoked.

Why the hook runs before the Ingrid Adapter: The Norce Checkout Order API invokes hooks ordered by their target, with /cart (sort order 3) before /shippings (sort order 4). The Ingrid Adapter registers its own hooks subscribing to /cart, /customer, and /state, all with target /shippings. Within a single cart-change transaction, the sequence is therefore:

  1. The Norce Commerce Adapter replaces /cart, and the delivery group values are wiped.
  2. The hook of the API consumer (target /cart) re-applies the delivery group indices to the working copy of the order.
  3. The Ingrid Adapter hook (target /shippings) maps the corrected cart into the Ingrid session.
  4. Everything is persisted in a single write, and only if every hook succeeded.

Ingrid Delivery Groups Sent to Ingrid

The Ingrid Shipping Adapter maps the Norce Checkout cart items into cart.groups on the Ingrid session request, one group per distinct logistics.delivery.group index. The example below is the Ingrid session request produced by the two-group Norce Checkout cart for order order-123 with PROD-001 in group 0 and PROD-002 in group 1.

{
  "cart": {
    "groups": [
      {
        "group_id": "order-123-group-0",
        "header": "Delivery 1",
        "contents": [
          { "sku": "PROD-001", "quantity": 1 }
        ]
      },
      {
        "group_id": "order-123-group-1",
        "header": "Delivery 2",
        "contents": [
          { "sku": "PROD-002", "quantity": 2 }
        ]
      }
    ]
  }
}

How Ingrid Delivery Groups Are Mapped Back to Norce Checkout

When the Ingrid Adapter maps an Ingrid session back to the Norce Checkout shipping object, each Ingrid delivery group becomes a separate entry in the shipping deliveries list. Each delivery carries its own reference (the Ingrid tos_id of that group), deliveryDetails (carrier, carrier product id, delivery class, product, pickup location), addons, price, vatRate, and items (sku and quantity).

Aggregation rules on the Norce Checkout shipping object when multiple Ingrid delivery groups exist:

  • total: the sum of all deliveries' prices, both including and excluding VAT. It is not taken from a single group.
  • name: reflects the selected shipping option(s). With a single delivery group, it is the carrier product name (for example FedEx International Connect Plus), falling back to the carrier name. With multiple delivery groups, it is the comma-joined list of distinct carrier names (for example FedEx, PostNord).
  • Root-level fields: fields at the root of the shipping object such as tmsReference, deliveryDetails, and addons are populated from the first delivery group for backward compatibility with integrations that expect a single shipment. Read the deliveries list to get per-shipment data.
  • shippingData: the complete Ingrid session, including all delivery groups, is stored in the shippingData attribute on the Norce Checkout shipping object as a JSON-encoded string. Consumers must parse that string to read the Ingrid session, as shown in the example below.

The deliveries list exists only in the shipping model of the V1 Norce Checkout Order API. Consumers on V0 get the backward-compatible root-level fields plus the full Ingrid session in the shippingData attribute.

{
  "shippings": [
    {
      "tmsReference": "01KGHX8V4MHCT77MT9DCGP4WC2",
      "deliveryDetails": {
        "carrier": "Best Transport",
        "carrierProductId": "TerminalCollect",
        "class": "pickup",
        "product": {
          "reference": "terminal-collect-0c062b9fec324907974e9a59b7dc9f7e",
          "name": "Best Terminal Collect"
        }
      },
      "deliveries": [
        {
          "reference": "01KGHX8V4MHCT77MT9DCGP4WC2",
          "deliveryDetails": { "carrier": "Best Transport", "class": "pickup" },
          "price": { "includingVat": 0, "excludingVat": 0 },
          "vatRate": 0.25,
          "items": [{ "sku": "PROD-001", "quantity": 1 }]
        },
        {
          "reference": "01KGHX8V4MVJAH0PPDGQWVHCD7",
          "deliveryDetails": { "carrier": "Best Transport", "class": "pickup" },
          "price": { "includingVat": 0, "excludingVat": 0 },
          "vatRate": 0.25,
          "items": [{ "sku": "PROD-002", "quantity": 2 }]
        }
      ],
      "attributes": {
        "shippingData": "{ ... full Ingrid session including delivery_groups ... }"
      }
    }
  ]
}

Ingrid Split Shipment Checklist for API Consumers

To use split shipment with the Ingrid Shipping Adapter, an API consumer must:

  1. Use the V1 Norce Checkout Order API if the per-delivery deliveries list is needed on the completed shipping. V0 consumers read the root-level shipping fields and the shippingData attribute instead.
  2. Register a hook with scope /cart and target /cart on every order that needs split shipment, directly after creating the order.
  3. In the hook, read the cart items from the request body, decide the grouping (for example per warehouse or per stock status), and respond with add patch operations for /cart/items/{index}/logistics/delivery with the value { "group": {group index} }, keeping the group indices sequential from 0.
  4. Renumber the delivery groups when an item is removed, so that no gap appears and the cart change is not rejected with ingrid-delivery-group-gap.
  5. On order completion, read shippings[].deliveries[] for the per-delivery Ingrid tos_id values (V1), or parse the shippingData attribute (V0, or when full Ingrid detail is needed).
  6. Optionally configure options.deliveryGroupHeaderTemplate on the Ingrid Adapter configuration to control the group headers shown in the Ingrid widget.

Remove Shipping

To remove an Ingrid shipping session from an order:

POST /api/checkout/v1/orders/{order_id}/shippings/{shipping_id}/remove
Host: {slug}.api-se.stage.norce.tech
x-merchant: {merchant}
x-channel: {channel}
Authorization: Bearer {token}

This will mark the shipping as removed in the Norce order.

Troubleshooting

Common Errors

  • Validation Error: Ensure order has country, culture, and currency set before creating a session.
  • 409 Conflict: An Ingrid shipping already exists for this order.
  • Empty Cart Error: Order must have at least one item.
  • Session Expired: Create a new shipping session.
  • Delivery Group Gap: Group indices must be sequential without gaps. Delivery group indices on the Norce Checkout cart items (logistics.delivery.group) must start at 0 with no missing index (for example 0,1,2). A gap fails the whole cart change and rolls it back, so the delivery group hook of the API consumer must renumber the remaining groups when an item is removed. Error code: ingrid-delivery-group-gap.
  • Split Shipment Collapses Into One Delivery: If an Ingrid split shipment turns back into a single delivery after the customer changes the cart, the delivery group indices were wiped by the cart update and not re-applied. Delivery groups are not preserved across cart changes in Norce Checkout, so the API consumer must register a hook subscribing to /cart with target /cart that re-assigns logistics.delivery.group on every cart change. See Required Cart Hook for Ingrid Split Shipment.

Shipping States

StateDescription
intentSession created, awaiting customer selection
processingOrder being processed, session validated
confirmedSession completed successfully
removedShipping removed from order