# Ingrid

The Ingrid Headless connector for the Kustom Shipping Assistant — setup credentials, how Ingrid delivery options map onto Kustom's selected_shipping_option, the per-country tax default you may need to override and how split shipments change the order structure.

Ingrid's Delivery Platform lets a merchant present tailored delivery options built from their own
shipping rules and carrier setup. Kustom connects to it through the **Ingrid Headless** TMS
connector in the Kustom Shipping Assistant, which fetches options from Ingrid during checkout and
maps them onto Kustom's order model — so the merchant works with one consistent order regardless
of where the options came from. This page is the field-level contract: what to configure, what
each attribute is populated from and what changes when an order is fulfilled by more than one
shipment.

## How the two systems divide the work

**Ingrid** owns the carriers, delivery options, pickup locations, addons and the merchant-facing
tooling in the Ingrid Merchant Platform (IMP).

**Kustom Checkout**, through KSA and the Ingrid Headless connector, requests options from Ingrid,
renders them to the buyer and records the buyer's choice on the order.

The lifecycle runs: order creation, shipping selection while the order is `checkout_incomplete`,
completion, then shipment booking with Ingrid after the fact.

## Setting up

### In Ingrid

Sign up for the Ingrid Merchant Platform and configure your carriers, delivery options and
shipping settings there. From Ingrid you need:

- Your **Ingrid Site ID**
- Your **Ingrid private key** — the plain key, **not** the base64-encoded variant

### In Kustom

Follow the general [Shipping Assistant setup](/checkout/shipping/#shipping-assistant), with these Ingrid-specific details.

| Portal field | Value |
| --- | --- |
| TMS | **Ingrid Headless**. Available in both Playground and Production |
| Identifier | Your Ingrid Site ID |
| Key | Your Ingrid private key, plain and not base64-encoded |

In Playground the connector talks to Ingrid's **staging** environment. In Production, it talks to
Ingrid's **production** environment.

**Digital products are the one deviation from the general guide.** They are handled on Ingrid's
side by tagging them with a `digital` tag, not through Kustom configuration, so skip the general
guide's digital-products step entirely.

Everything else — activating KSA in the Portal, triggering KSA in the checkout payload and
verifying in Playground — is unchanged.

### Merchants running a dual-iframe checkout

Some merchants run an Ingrid iframe above a Kustom iframe during a transition period, and need to
keep collecting a shipping address without yet showing Ingrid-sourced options inside Kustom. Pass
`options.tms_configuration_override.disabled` as `true` when creating the order: Kustom then
collects the address but doesn't fetch options from Ingrid.

## Pre-purchase: how the selected option is populated

While the order's `status` is `checkout_incomplete`, `selected_shipping_option` — present in both
the order response and the callbacks — describes the buyer's choice. Its fields come from Ingrid
like this:

| Field | Mapped from |
| --- | --- |
| `id` | The shipping option ID generated by Ingrid |
| `name` | The `display_name` of the Ingrid `delivery_category`, falling back to the carrier's product name |
| `description` | Not provided |
| `promo` | Not provided |
| `price` | The price of the Ingrid `delivery_option` |
| `preselected` | Not provided |
| `tax_rate` | Defaulted by KSA from a per-country table — see below |
| `tax_amount` | Derived from that defaulted `tax_rate` |
| `shipping_method` | KSA's mapping of Ingrid's delivery type and location type |
| `tms_reference` | Post-purchase only — Ingrid's session ID |
| `tos_id` | Post-purchase only |

### Shipping method mapping

`shipping_method` is derived from Ingrid's `delivery_type` and, where present, `location_type`:

| Ingrid delivery type | Ingrid location type | KSA `shipping_method` |
| --- | --- | --- |
| — | `LOCATION_TYPE_UNSPECIFIED` | No effect — falls through to the delivery type rows below |
| — | `LOCKER` | `BoxUnreg` |
| — | `STORE` | `PickUpPoint` |
| — | `POSTOFFICE` | `PickUpPoint` |
| — | `MANNED` | `PickUpPoint` |
| `DELIVERY_TYPE_UNSPECIFIED` | — | `Undefined` |
| `DELIVERY` | — | `Home` |
| `MAILBOX` | — | `Postal` |
| `PICKUP` | — | `PickUpPoint`, or `Home` when no locations are available |
| `INSTORE` | — | `PickUpStore`, or `Home` when no locations are available |

### Delivery details

`selected_shipping_option.delivery_details` carries the carrier and logistics detail:

- `carrier` — KSA's supported carrier, decoded from the prefix of Ingrid's carrier product ID,
  falling back to Ingrid's carrier name
- `class` — always `STANDARD`
- `product.identifier` — Ingrid's carrier product ID, post-purchase only
- `product.name` — Ingrid's carrier name, post-purchase only
- `timeslot.id` — Ingrid's shipping option ID for the timeslot
- `timeslot.start`, `timeslot.end` — the timeslot bounds
- `pickup_location.id` — Ingrid's numeric location ID
- `pickup_location.name`, `pickup_location.address` — the location

### Selected addons

`selected_shipping_option.selected_addons` is an array with one entry per chosen addon:
`display_name`, `type` (the addon's `external_id` in Ingrid, or Ingrid's addon ID when it has
none), `price` and `external_id` (Ingrid's addon ID).

## Tax on shipping options is defaulted, not calculated

Ingrid doesn't calculate tax, so KSA supplies the selected option's `tax_rate` itself and derives
`tax_amount` from it. By default that rate comes from a per-country table — **25%** for SE, NO
and DK, **25.5%** for FI, **19%** for DE, and 25% for any country not listed. In a market the
table doesn't cover, that fallback is a guess and you'll overpay tax if you leave it.

Two other modes exist and are enabled per merchant by Kustom: one takes the lowest tax rate
among the order's non-shipping lines, the other derives an effective rate proportionally across
the cart's tax groups. Ask which one your account is on before assuming the table applies.

Override it by implementing the shipping option update callback and returning one or more
`shipping_fee` order lines on the order in the callback response. Those lines replace the
defaulted `tax_rate` and `tax_amount`. Compute the rate from the cart, not from a constant.

## Merchant references must be sent before completion

`merchant_reference1` — or `merchant_reference2` when the first is missing — is propagated to
Ingrid as the delivery's `external_id`, so that orders can be found in the Ingrid Merchant
Platform.

Send them **before the order is completed**. Two consequences follow from Kustom not updating the
Ingrid session after completion:

- If the references are missing at completion time, Kustom sends its own `order_id` as the Ingrid
  delivery's `external_id` instead.
- Sending merchant references to the Order Management API afterwards will **not** reach Ingrid.
  There's no way to correct it later.

## Post-purchase: booking the shipment

Shipping information stays available after completion. Both `tms_reference` and `tos_id` are on
`selected_shipping_option`, in the Checkout API and the Order Management API alike.

To fulfill the order, create and book the shipment with Ingrid through Ingrid's SOM API, passing the
`tos_id` from the order's `selected_shipping_option`. Because the Ingrid Headless API shares most
of its model with Ingrid's delivery checkout API, the `tos_id` alone is enough — Ingrid fills in
the rest. If another system needs more detail, use the `tos_id` to fetch the full shipment
information from Ingrid's `sessions_summaries.list` API.

## Split shipments

An order can be fulfilled by more than one shipment — goods from multiple warehouses, or items
that must ship separately for any other reason. The pre-purchase and post-purchase flows are
nearly identical. What changes is the order structure.

### Deliveries

The `deliveries` array describes each shipment. Every order line except those of `type`
`gift_card` and `store_credit` must be assigned to one, through
`order_lines[].shipping_attributes.delivery_id`. There's no limit on the number of deliveries.

```json
{
  "deliveries": [
    {
      "id": "Shipment-1",
      "title": "Shipment 1",
      "description": "Refrigerated goods",
      "readiness": [
        {
          "earliest": "2026-03-16T08:40:34.865Z",
          "latest": "2026-03-17T08:40:34.865Z",
          "attributes": ["premium"]
        }
      ],
      "origins": [{ "external_id": "cold-storage-1" }]
    },
    {
      "id": "Shipment-2",
      "title": "Shipment 2",
      "description": "Dry goods",
      "readiness": [
        {
          "earliest": "2026-03-16T08:40:34.865Z",
          "latest": "2026-03-17T08:40:34.865Z",
          "attributes": ["economy"]
        }
      ],
      "origins": [{ "external_id": "warehouse-1" }]
    }
  ],
  "order_lines": [
    {
      "type": "physical",
      "reference": "salmon-001",
      "name": "Fresh Salmon Fillet",
      "quantity": 1,
      "shipping_attributes": { "delivery_id": "Shipment-1" }
    },
    {
      "type": "physical",
      "reference": "pasta-001",
      "name": "Spaghetti 500g",
      "quantity": 3,
      "shipping_attributes": { "delivery_id": "Shipment-2" }
    }
  ]
}
```

### Selected shipping options, plural

A split-shipping order has more than one selected option, so the Checkout API, the callback API
and the Order Management API all expose a `selected_shipping_options` array, with one entry per
selected option and the same structure as the singular field.

The two are **mutually exclusive**. With exactly one selected option you get
`selected_shipping_option` and no array; with more than one you get the array and no singular
field at all — it is omitted, not left holding the first of them. So branch on which of the two
is present rather than reading the singular one and hoping.

## Related

- [Shipping Assistant setup](/checkout/shipping/#shipping-assistant) — the general KSA setup this page deviates from
- [Shipping partners](/partners/shipping-partners/) — the other TMS connectors
- [Create the order](/checkout/integrate/create-order/) — where `deliveries` and `merchant_reference1` are set
- [Update or cancel an order](/order-management/update-and-cancel/) — reading `selected_shipping_option` after completion
- [Order management](/order-management/) — why post-completion updates don't reach Ingrid
