Skip to main content

External Shipping Engine: Storefront API Integration Draft

warning

This document is a draft and what it contains is not available yet in any environment, and is subject to change.

This page covers the Storefront API surface for ESE integrations — querying shipping methods, selecting them, and fetching pickup locations. For the backend webhook contract, see the ESE protocol reference. For a reference of all new shipping fields and types introduced alongside ESE, see New Shipping Capabilities in Storefront API.


Get Shipping Methods

Key Principle

The frontend controls when Centra queries the ESE by choosing whether to include shippingMethods in its selection set. Background notifications happen automatically — the frontend does not control them and does not need to handle them.

shippingMethods is a field on CheckoutSelection, which is the type of the checkout field on Selection. When any Storefront API operation returns a Selection and the client has included checkout { shippingMethods } in its selection set, Centra queries the ESE synchronously before responding. If shippingMethods is not requested, Centra may still notify the ESE in the background but responds immediately without waiting for shipping options.

The following fragment includes all available fields on ShippingMethod:

fragment SelectionWithShipping on Selection {
checkout {
shippingMethods {
id
name
selected
comment
hasLocation
carrierName
serviceCode
deliveryType
description
iconUrl
price {
value
currency
}
originalPrice {
value
currency
}
etd {
relative { min max units }
absolute { from to }
custom
}
labels {
type
displayName
description
iconUrl
}
customerChoices {
id
displayName
description
type
default
price { value currency }
options { key displayName description price { value currency } }
}
selectedLocation {
id
displayName
address {
address1
city
zipCode
country { name }
}
latitude
longitude
distanceMeters
openingHours { dayOfWeek opens closes }
openingHoursText
brickAndMortar
}
locations {
id
displayName
address {
address1
city
zipCode
country { name }
}
latitude
longitude
distanceMeters
openingHours { dayOfWeek opens closes }
openingHoursText
brickAndMortar
}
}
}
}

How Centra Calls the ESE

Centra calls the ESE in two distinct modes:

  • Notified: A fire-and-forget call Centra makes to the ESE backend whenever a session-level change occurs — for example, a shipping address update, a language change, or an item being added to the cart. No shipping options are returned. This happens transparently in the background; the frontend receives an instant response. Centra reserves the right to determine which session changes trigger a notification.

  • Queried: A blocking call Centra makes when the frontend explicitly requests shippingMethods on CheckoutSelection. This field is specific to the checkout flow. Centra waits for the ESE to respond before completing the API response (up to 10 seconds), and the returned shipping options are surfaced to the frontend.

Behaviour per Operation

OperationshippingMethods requestedESE notifiedESE queriedResponse
selection (query)NoNoNoInstant
selection (query)YesNoYesSlow (up to 10s)
setAddressNoYesNoInstant
setAddressYesYesYesSlow (up to 10s)
addItemNoYesNoInstant
addItemYesYesYesSlow (up to 10s)

The same pattern applies to all operations that modify session state. Read queries (such as selection) only trigger an ESE call when shippingMethods is requested.

ShippingMethod Fields

FieldTypeDescription
idInt!Unique identifier for the shipping method
nameString!Human-readable name shown to the customer
priceMonetaryValue!The effective price of this shipping method
originalPriceMonetaryValuePre-discount price, if applicable — use to display a crossed-out original price
selectedBoolean!Whether this method is currently selected on the checkout
commentStringOptional commentary about the shipping method
hasLocationBoolean!Whether this method supports selectable pickup/drop-off locations. Use this as the authoritative capability flag — an empty locations array does not mean locations are unavailable, only that none were returned for the current address context
locations[ShippingMethodLocation]Pickup/drop-off locations pre-populated by the ESE based on the current shipping address. May be empty — use getShippingMethodLocations to search for locations at a different address or to retrieve more results
carrierNameStringName of the shipping carrier
serviceCodeStringCarrier service identifier
deliveryTypeStringFulfillment method — recommended values: TO_DOOR, PICKUP, LOCKER, MAILBOX, STANDARD_SHIPMENT
descriptionStringAdditional details about the option
iconUrlStringURL to the carrier's icon
etdShippingETDEstimated time of delivery. At least one of relative, absolute, or custom is provided — custom takes precedence when present
labels[ShippingLabel]Visual indicators attached to the option (e.g. sustainability badge, signature required)
customerChoices[CustomerChoice]Customer-configurable selections for this option — INPUT (text entry), CHECKBOX (toggle), or CHOICE (dropdown with sub-options)
selectedLocationShippingMethodLocationThe pickup/drop-off location currently attached to this method, or null if none has been set or the method does not support locations

Advantages

  • No new API parameters or separate triggering calls needed — the ESE is queried purely based on what fields are selected.
  • Easy to reason about: if you want shipping methods, include them in your query; Centra does the rest.
  • Frontend controls the tradeoff between response speed and data completeness.

Considerations

  • Requesting shippingMethods will significantly slow the response (up to 10 seconds).
  • If the ESE is slow or unavailable, the entire mutation response is delayed. Design your loading states accordingly.
  • The frontend is responsible for choosing the right moment to trigger an ESE query.

Both patterns share the same starting point:

1. User adds item to cart — instant (ESE notified in background)

mutation {
addItem(item: { product: 1, quantity: 1 }) {
selection {
lines { quantity product { name } }
}
}
}

2. User arrives at checkout — instant, page renders

query {
selection {
checkout {
shippingAddress { city country }
}
}
}

From here, two patterns diverge depending on your UX requirements.

Pattern 1: Combined

Set the address and fetch shipping methods in a single call.

3. User sets address and fetches shipping methods — up to 10 seconds (ESE queried)

mutation {
setAddress(shippingAddress: { ... }) {
selection {
checkout {
shippingAddress { city country }
shippingMethods { id name selected hasLocation price { value currency } }
}
}
}
}

Trade-off: Simpler orchestration, but the address update blocks for up to 10 seconds while the ESE responds.

Set the address instantly, then fetch shipping methods in a separate background call.

3. User sets address — instant (ESE notified in background)

mutation {
setAddress(shippingAddress: { ... }) {
selection {
checkout { shippingAddress { city country } }
}
}
}

4. Immediately fire: fetch shipping methods — up to 10 seconds (ESE queried)

query {
selection {
checkout {
shippingMethods { id name selected hasLocation price { value currency } }
}
}
}

Trade-off: More orchestration on the frontend, but the address update is instant and the shipping selector appears once ready.

Shipping Methods per Delivery Group

When an order spans multiple delivery groups (e.g. items from different warehouses), each group can have its own set of available shipping methods. shippingMethods is a new field added to SelectionDeliveryGroup — the delivery group type within CheckoutSelection — and is not present on the base DeliveryGroup type used elsewhere (e.g. in order history).

query {
selection {
checkout {
deliveryGroups {
id
shippingMethods {
id
name
hasLocation
price { value currency }
}
items {
quantity
product { name }
}
}
}
}
}

Including shippingMethods inside deliveryGroups triggers a single ESE query, the same as checkout.shippingMethods — the ESE response is what determines the options available per group.


Get Shipping Method Locations

Some shipping methods — such as parcel shop networks or click-and-collect points — require the customer to choose a physical pickup or drop-off location. These are fetched via getShippingMethodLocations, which maps to the ESE's optionLocation request.

Fetching Locations

warning

Only call getShippingMethodLocations when ShippingMethod.hasLocation is true — only render the location picker UI for methods that support it.

When ShippingMethod.locations is already populated, you may not need to call getShippingMethodLocations at all — the ESE has pre-fetched nearby locations as part of the checkout response. Use getShippingMethodLocations when you need to search at a different address, retrieve more results, or when locations came back empty.

getShippingMethodLocations accepts a shipping method ID and an optional location hint. The hint can be an Address, geographic coordinates, or omitted entirely — in which case the selection's current shipping address is used.

# Using an address
query {
getShippingMethodLocations(
shippingMethodId: 42
address: {
address1: "14 Downing Street"
city: "London"
zipCode: "SW1A 2AA"
country: "GB"
}
) {
id
displayName
address {
address1
city
zipCode
country { name }
}
openingHours {
dayOfWeek
opens
closes
}
}
}

# Using coordinates
query {
getShippingMethodLocations(
shippingMethodId: 42
latitude: 51.5033
longitude: -0.1276
) {
id
displayName
address {
address1
city
zipCode
country { name }
}
openingHours {
dayOfWeek
opens
closes
}
}
}

# Defaulting to the selection's shipping address
query {
getShippingMethodLocations(
shippingMethodId: 42
) {
id
displayName
address {
address1
city
zipCode
country { name }
}
openingHours {
dayOfWeek
opens
closes
}
}
}

Exactly one location hint strategy applies per call. Providing both address and coordinates is an error.

ShippingMethodLocation Fields

FieldTypeDescription
idInt!Unique identifier for this location
displayNameString!Human-readable name of the location
addressAddressPhysical address of the location
latitudeFloatGeographic latitude of the location
longitudeFloatGeographic longitude of the location
distanceMetersFloatDistance in meters from the shipping address to this location
openingHours[OpeningHoursEntry]Opening hours per day of week
openingHoursTextStringHuman-readable opening hours summary
brickAndMortarIntID of a Centra brick-and-mortar store that may fulfill the order

Set Shipping Method

Storefront API reference

Pass back the id received from ShippingMethod.id in the shippingMethods response — no difference in behaviour whether the method comes from Centra or an ESE.

If the method supports locations (hasLocation: true), you can attach the customer's chosen location in the same call via the optional locationId parameter (using ShippingMethodLocation.id from getShippingMethodLocations). The selected location is then readable back on checkout.shippingMethod.selectedLocation.

warning

Use setShippingMethod only when the selection has no delivery groups, and setDeliveryGroupShippingMethod only when it does. Using the wrong mutation for the selection's structure will result in an error.

# Without a location
mutation {
setShippingMethod(id: 12) {
selection {
checkout { shippingMethod { id name } }
}
}
}

# With a location
mutation {
setShippingMethod(id: 12, locationId: 7) {
selection {
checkout {
shippingMethod {
id
name
selectedLocation {
id
displayName
address { address1 city zipCode country { name } }
}
}
}
}
}
}

Setting a Shipping Method per Delivery Group

When the checkout has multiple delivery groups, each group may have its own set of available shipping methods. A dedicated setDeliveryGroupShippingMethod mutation handles this case. This mutation is new and specific to ESE delivery group checkouts.

# Without a location
mutation {
setDeliveryGroupShippingMethod(deliveryGroupId: 1, shippingMethodId: 12) {
selection {
checkout {
deliveryGroups {
id
shippingMethods { id name selected }
}
}
}
}
}

# With a location
mutation {
setDeliveryGroupShippingMethod(deliveryGroupId: 1, shippingMethodId: 12, locationId: 7) {
selection {
checkout {
deliveryGroups {
id
shippingMethods {
id
name
selected
selectedLocation { id displayName }
}
}
}
}
}
}

Session as Integration Anchor Point

Because shipping options are tied to the session, the session ID can serve as a stable anchor for frontend integrations with third-party shipping providers. For example, a provider like Ingrid can associate customer-specific delivery promises — such as "This item can be with you in 3 days" — directly with the Centra session, without requiring a separate authentication flow on the frontend.

Your frontend widget can contact the provider directly using the session token, and the provider's backend can correlate that with the corresponding Centra ESE session context.

Shipping Metadata

The ESE may return shippingProviderMetadata in both NOTIFY and CHECKOUT responses. When Centra receives them, it silently attaches them to the Session — they are available on the session without the frontend needing to do anything extra. This allows the ESE to propagate provider-specific metadata (delivery window tokens, session identifiers, widget configuration, delivery promises, etc.) that the frontend or widget can read back from the session. Keys and values are defined by the ESE provider — Centra passes them through without interpretation. Each entry also carries provider and version to identify the source.

query {
session {
shippingProviderMetadata {
key
value
provider
version
}
}
}

Nota Bene: Backend-Only Calls

The ESE protocol includes additional request types — testConnection and orderCreated — that Centra uses for backend-to-backend operations. These are handled entirely server-side and have no frontend surface. You do not need to account for them in your Storefront API integration.

note

The impact of ESE on express checkout flows (e.g. Shop Pay, Apple Pay) is still under discussion.