New Shipping Capabilities in Storefront API Draft
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 new shipping fields and mutations available in the Storefront API — enriched shipping method data, pickup locations, updated set mutations, and shipping provider metadata on sessions, methods, and locations.
Get Shipping Methods
checkout.shippingMethods accepts an optional optimizeFor argument — an enum that filters the returned shipping methods for a specific display context. When omitted, the full standard set is returned.
| Value | Context |
|---|---|
"applepay" | Apple Pay payment sheet |
"googlepay" | Google Pay payment sheet |
"ams" | AMS |
ShippingMethod
ShippingMethod is available on checkout.shippingMethods and checkout.deliveryGroups[].shippingMethods (the list of available options), and on checkout.shippingMethod and checkout.deliveryGroups[].shippingMethod (the currently selected method).
| Field | Type | Status | Description |
|---|---|---|---|
id | Int! | Existing | Unique identifier for the shipping method |
externalId | String | New | The original shipping method identifier returned by the ESE. null for methods not originating from an external shipping provider |
name | String! | Existing | Plain text, max 50 characters. The primary customer-facing label for the shipping option |
price | MonetaryValue! | Existing | Effective price. See MonetaryValue for sub-fields |
originalPrice | MonetaryValue | New | Pre-discount price, shown struck through next to price. null when there is no discount. When present, always strictly greater than price |
selected | Boolean! | Existing | Whether this method is currently selected on the checkout |
carrierName | String | New | Customer-facing carrier or brand name (e.g. "DHL Express", "Eco delivery"). null when the method does not originate from an external shipping provider |
serviceCode | String | New | Machine-readable carrier service identifier (e.g. "EXPRESS", "PICKUP"). Not for customer display. null when the method does not originate from an external shipping provider |
deliveryType | DeliveryType | New | Fulfillment method. One of: TO_DOOR, PICKUP, LOCKER, MAILBOX, OTHER. See DeliveryType values. null when the method does not originate from an external shipping provider |
description | String | New | Short plain-text subtitle, max 120 characters, no markup or newlines (e.g. "Next business day delivery"). null when not supplied by the provider |
iconUrl | String | New | HTTPS URL to a square SVG image (1:1 aspect ratio). The frontend is responsible for sizing. null when not supplied by the provider |
etd | ShippingETD | New | Estimated time of delivery. See ShippingETD. null when not supplied by the provider |
labels | [ShippingLabel] | New | Visual indicators attached to the option. Max 5 entries. Empty array when none (never null). See ShippingLabel |
customerChoices | [CustomerChoice] | New | Customer-configurable selections. Max 10 entries. Empty array when none (never null). See CustomerChoice |
hasLocation | Boolean! | New | Whether this method supports selectable pickup/drop-off locations. Use this as the authoritative capability flag |
locations | [ShippingMethodLocation] | New | Pickup/drop-off locations pre-populated by the ESE for the current shipping address. May be empty even when hasLocation is true — when empty, call getShippingMethodLocations with the order address to retrieve locations |
selectedLocation | ShippingMethodLocation | New | The location currently attached to this method, or null if none has been set |
shippingProviderMetadata | [ShippingProviderMetadata] | New | Provider-defined key/value metadata attached to this shipping method by the ESE. Same structure as Session.shippingProviderMetadata |
MonetaryValue
| Sub-field | Type | Description |
|---|---|---|
value | Float! | Numeric amount |
currency | String! | ISO 4217 currency code (e.g. "SEK", "EUR") |
formattedValue | String! | Display-ready string (e.g. "50.00 SEK") |
DeliveryType values
| Value | Description |
|---|---|
TO_DOOR | The parcel is delivered directly to the customer's address by a carrier. |
PICKUP | The customer collects the parcel from a designated pickup point. |
LOCKER | The parcel is delivered to an automated parcel locker. |
MAILBOX | A small parcel or letter-sized shipment delivered directly into the customer's physical mailbox. |
OTHER | Catch-all for delivery types not covered by the values above. |
Frontends should handle all five values. OTHER is the safe fallback rendering.
Full fragment:
fragment ShippingMethodFields on ShippingMethod {
id
externalId
name
selected
hasLocation
carrierName
serviceCode
deliveryType
description
iconUrl
price { value currency formattedValue }
originalPrice { value currency formattedValue }
etd {
relative { min max units }
absolute { from to }
custom
}
labels {
type
displayName
description
iconUrl
}
customerChoices {
id
displayName
description
type
default
price { value currency formattedValue }
options { key displayName description price { value currency formattedValue } }
}
selectedLocation {
id
displayName
address { address1 city zipCode country { name } }
latitude
longitude
distanceMeters
openingHours { periods { open { day hour minute } close { day hour minute } } specialDays { date { year month day } isClosed comment } }
openingHoursText
brickAndMortar
shippingProviderMetadata { provider data { key value } }
}
locations {
id
displayName
address { address1 city zipCode country { name } }
latitude
longitude
distanceMeters
openingHours { periods { open { day hour minute } close { day hour minute } } specialDays { date { year month day } isClosed comment } }
openingHoursText
brickAndMortar
shippingProviderMetadata { provider data { key value } }
}
shippingProviderMetadata { provider data { key value } }
}
ShippingMethodLocation
Represents a physical pickup or drop-off location. Appears on ShippingMethod.locations, ShippingMethod.selectedLocation, and as the return type of getShippingMethodLocations.
| Field | Type | Description |
|---|---|---|
id | String! | Unique identifier for this location |
displayName | String! | Human-readable name of the location |
address | Address | Physical address |
latitude | Float | Geographic latitude |
longitude | Float | Geographic longitude |
distanceMeters | Float | Distance in meters from the current shipping address to this location |
openingHours | OpeningHours | Regular opening hours and special day exceptions. See OpeningHours |
openingHoursText | String | Human-readable opening hours summary |
brickAndMortar | Int | ID of a Centra brick-and-mortar store associated with this location, or null if none. When present, indicates the order may be fulfilled by that physical store |
shippingProviderMetadata | [ShippingProviderMetadata] | Provider-defined key/value metadata attached to this location by the ESE. Same structure as Session.shippingProviderMetadata |
OpeningHours
| Field | Type | Description |
|---|---|---|
periods | [OpeningHoursPeriod] | Regular weekly opening hours as a list of open/close periods |
specialDays | [SpecialDay] | Exceptions to the regular schedule (holidays, closures, etc.) |
OpeningHoursPeriod
Each period has an open point and an optional close point. close is null for locations that are open 24 hours. A period can span midnight (e.g. open Monday 09:00, close Tuesday 02:00).
| Field | Type | Description |
|---|---|---|
open | OpeningHoursPoint! | When the period starts |
close | OpeningHoursPoint | When the period ends. null means open 24 hours |
OpeningHoursPoint
| Field | Type | Description |
|---|---|---|
day | Int! | Day of week: 0 = Sunday, 1 = Monday, …, 6 = Saturday |
hour | Int! | Hour in 24-hour format (0–23) |
minute | Int! | Minute (0–59) |
SpecialDay
| Field | Type | Description |
|---|---|---|
date | SpecialDayDate! | Calendar date of the exception |
isClosed | Boolean! | Whether the location is closed for the entire day |
comment | String | Human-readable note (e.g. "Christmas Day") |
SpecialDayDate
| Field | Type | Description |
|---|---|---|
year | Int! | Year (e.g. 2026) |
month | Int! | Month (1–12) |
day | Int! | Day of month (1–31) |
ShippingMethod.locations may be pre-populated by the ESE when shipping methods are fetched, but it can be empty even when hasLocation is true. When locations is empty, call getShippingMethodLocations with the order address as the search address to retrieve locations. Also use it to search at a different address or retrieve more results. Only call it when hasLocation is true.
# Search by 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 { periods { open { day hour minute } close { day hour minute } } specialDays { date { year month day } isClosed comment } }
distanceMeters
}
}
# Search by coordinates
query {
getShippingMethodLocations(shippingMethodId: 42, latitude: 51.5033, longitude: -0.1276) {
id
displayName
address { address1 city zipCode country { name } }
distanceMeters
}
}
# Default to the selection's current shipping address
query {
getShippingMethodLocations(shippingMethodId: 42) {
id
displayName
address { address1 city zipCode country { name } }
distanceMeters
}
}
Omitting both address and coordinates defaults to the selection's current shipping address. Providing both is an error.
ShippingETD
Estimated time of delivery. Any combination of sub-fields can coexist. When custom is present, we recommend displaying it to the customer in place of any label derived from relative or absolute — Centra does not enforce this on the backend.
| Field | Type | Description |
|---|---|---|
relative | ShippingETDRelative | Range expressed as min, max, and units. min and max are positive integers (>= 1). min can equal max (exact estimate — render "2 days", not "2–2 days"). units is one of: HOURS, DAYS, BUSINESS_DAYS, WEEKS |
absolute | ShippingETDAbsolute | Date range with from and to as ISO 8601 datetimes with timezone offset (e.g. "2026-02-25T08:00:00-05:00") |
custom | String | Plain text, max 80 characters (e.g. "Delivered by Christmas") |
ShippingLabel
Visual indicators attached to a shipping option — sustainability badges, signature-required notices, and similar.
| Field | Type | Description |
|---|---|---|
type | String! | Machine-readable label type. See known values below |
displayName | String! | Plain text, max 30 characters. Customer-facing label name |
description | String | Plain text, max 120 characters. null when not supplied |
iconUrl | String | HTTPS URL to a square SVG image (1:1 aspect ratio). null when not supplied |
ShippingLabel type values
The following values are currently defined. New values may be added over time — always handle unknown values gracefully.
| Value | Description |
|---|---|
SUSTAINABILITY | Indicates an environmentally friendly shipping option |
SIGNATURE_REQUIRED | Delivery requires a recipient signature |
FASTEST | The fastest available shipping option |
CHEAPEST | The cheapest available shipping option |
OTHER | A provider-specific label type not covered by the values above |
CustomerChoice
Customer-configurable selections attached to a shipping method. Four interaction types are supported: INPUT (text entry), CHECKBOX (toggle), CHOICE (dropdown with sub-options), and TIMESLOT (delivery time window selection).
| Field | Type | Description |
|---|---|---|
id | String! | Identifier for this choice |
displayName | String! | Label shown to the customer |
description | String | Explanatory text |
type | String! | INPUT, CHECKBOX, CHOICE, or TIMESLOT |
default | String | Default value. For INPUT: shown in the input box, defaults to empty. For CHOICE and TIMESLOT: the option with the matching key is pre-selected, defaults to the first option. For CHECKBOX: "1" means checked, defaults to unchecked |
price | MonetaryValue | Additional cost on top of the base shipping price (additive, not a replacement). Display as "+X.XX". null when the choice has no extra cost |
options | [CustomerChoiceOption] | Sub-options — required when type is CHOICE or TIMESLOT. Max 10 entries |
Type-specific constraints:
INPUT— max customer entry: 80 characters.CHECKBOX— no additional constraints.CHOICE—optionsis required. Max 10 options.TIMESLOT—optionsis required. Max 10 options. Each option'sdisplayNamecarries the pre-formatted time window (e.g."Mon 25 Feb, 09:00–12:00").
CustomerChoiceOption
| Field | Type | Description |
|---|---|---|
key | String! | Choice identifier |
displayName | String! | Customer-facing label |
description | String | Explanatory text |
price | MonetaryValue | Overrides the parent CustomerChoice.price when set. Same semantics — additive on top of the base shipping price |
Set Shipping Method
setShippingMethod now accepts an optional locationId parameter. When provided, the chosen pickup or drop-off location is attached to the method in the same call. The selected location is then readable on checkout.shippingMethod.selectedLocation.
# Without a location
mutation {
setShippingMethod(id: 12) {
selection {
checkout {
shippingMethod { id name }
}
}
}
}
# With a location
mutation {
setShippingMethod(id: 12, locationId: "loc-7") {
selection {
checkout {
shippingMethod {
id
name
selectedLocation {
id
displayName
address { address1 city zipCode country { name } }
}
}
}
}
}
}
When the checkout has multiple delivery groups, use setDeliveryGroupShippingMethod instead. The locationId parameter works the same way.
# 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: "loc-7") {
selection {
checkout {
deliveryGroups {
id
shippingMethods {
id
name
selected
selectedLocation { id displayName }
}
}
}
}
}
}
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.
External Provider Shipping Metadata
shippingProviderMetadata is available on Session, ShippingMethod, and ShippingMethodLocation — an array of provider-grouped metadata entries that a shipping provider integration can attach server-side. The frontend does not need to do anything to populate it; Centra stores and exposes it automatically whenever it receives metadata from the provider.
Each entry groups all metadata from a single provider:
| Field | Type | Description |
|---|---|---|
provider | String! | Identifier of the shipping provider that set these entries |
data | [ShippingProviderMetadataEntry!]! | Key/value pairs defined by the provider |
ShippingProviderMetadataEntry:
| Field | Type | Description |
|---|---|---|
key | String! | Metadata key, defined by the provider |
value | String! | Metadata value, defined by the provider |
query {
session {
shippingProviderMetadata {
provider
data {
key
value
}
}
}
}
Keys and values are defined by the provider — Centra passes them through without interpretation. Typical contents include:
- Delivery window tokens — identifiers the provider uses to track a promised delivery slot
- Widget initialization data — a session token or config blob a third-party shipping widget can use to bootstrap itself on the frontend, without requiring a separate authentication step
- Delivery promises — human-readable strings such as
"Delivered by Tuesday" - Session correlation IDs — references the provider backend uses to look up the corresponding session on their side
This makes shippingProviderMetadata a general-purpose side-channel between the shipping provider's backend and your frontend: the provider writes to it, and the frontend reads it back from the session.
Express Checkout
Express checkout flows (e.g. Shop Pay, Apple Pay) are fully supported. Centra handles the ESE integration transparently — no additional frontend implementation is required.