Storefront API
Shopper-facing lookups that power delivery choices on your webstore or app. Fetch the delivery options a shopper can pick, live carrier rates for a route, a per-product delivery promise for product pages, the eligible fulfillment or collection locations near a customer, and phone-number validation. Every call is stateless: none of them creates an order or a shipment.
Before you start
- Every request carries
Authorization: Bearer <token>,x-api-keyandtenant-id; see the Authentication API. - A tenant is your Carriyo account. A merchant is a brand or store within it, identified by an uppercase code such as
ACME, not its display name. - Any field named
partner_*is your identifier, not Carriyo's:partner_location_codeis the location code you chose, whilepartner_location_idandlocation_idare Carriyo's, in the formACCOUNT_<uuid>. - Delivery options are configured per merchant in the Dashboard, and only
ACTIVEones are evaluated here. - These lookups run on every page view, so they are rate limited per plan. See the API conventions for the limits and the retry advice.
Storefront
Shopper-facing evaluations for your webstore or app. Given a cart, a product, or a customer location, these lookups return the delivery choices, rates, promises, and pickup or fulfillment locations to show the shopper.
They are stateless: no order or shipment is created. Storefront frontends and headless commerce middleware call them, so they run at higher volume than the per-shipment management endpoints. To manage the delivery options behind these lookups, see the delivery-options endpoints in the Core API.
Related: How delivery options are configured and evaluated
4 operations · 0 objects
/storefront/delivery-optionsGet delivery options
Returns the delivery options that match a cart at checkout, evaluated against the merchant's configured conditions.
Behavior
What to send
merchant and at least one line item are required. Every other field is read only when a configured condition needs it:
order_datefor working and blackout dayscustomerfor geographypayment.order_totalfor order valuepayment.payment_on_deliveryfor payment type- line-item weights for weight
- line-item categories for product and
item_product_categoriesconditions
Line items resolve to catalog products by product_ref or product_id. sku is not a lookup key; it only supplies the line's id when you omit one. A line that matches no catalog product is not rejected: it stays unresolved and is never stock-evaluated.
customer is where the shopper is: the delivery destination for DELIVERY options and the anchor for each COLLECTION option's collection points. All three delivery methods are returned unless delivery_methods narrows them.
fulfillment_locations narrows the whole answer to the named locations: options are matched against their location allowlists, each entry lists only those locations, and its fee and estimated arrival window are computed from them. With inventory_check the stock read is narrowed too.
What comes back
Each entry carries a shipping_fee, an estimated arrival window and, for COLLECTION options, its collection points under customer_collection_locations. With inventory_check, it also carries an availability verdict per item and for the whole cart.
Each entry is a single-delivery fact: one shipping_fee, one estimated arrival window, one availability verdict, and the fulfillment_locations that can each alone provide exactly that answer. Everything it marks available ships together in one delivery from any one of those locations; an entry never claims fulfillment across several locations.
When stock was evaluated, entries are banded by availability, FULL first, then every other entry by how many line items it can supply, most first, and ordered by sort_by and sort_direction within each band. When stock was not evaluated, ordering is sort_by and sort_direction alone. With the default SPEED, the first entry is the fastest option that can deliver the whole cart, whenever stock was checked and one exists.
Shipping fee
FREE_OF_COSToptions return0.PAIDoptions resolve a fixed or tiered fee.PASS_THROUGHoptions return a live carrier quote fromparcelsand the line items. Withoutparcels, or when no rate is quoted, the option is returned with an emptyshipping_fee.
The request currency selects which of the option's pricing entries applies but does not force the currency of the answer. The entry is chosen in a fixed order:
- the entry matching the request currency
- the option's default-currency entry
- the first configured entry, only when the option has no default currency
A configured default currency that matches no entry yields an empty fee. Always render the returned shipping_fee.currency.
- An empty
shipping_feemeans no price could be resolved: no tier contained the order total, no currency matched, or no carrier rate was quoted. It is not free shipping. - A tiered fee ending in a free tier reports that tier's
min_valueasfree_shipping_threshold, independent of the cart value, and it stays present even when the fee amount could not be resolved. - An option whose fee lookup fails outright is dropped rather than shown unpriced.
- The fee is evaluated against the cart as sent, even on a
PARTIALentry. Requote each chosen subset with its ownpaymentfor exact per-delivery fees.
Stock (inventory_check)
The stock check runs only when inventory management is enabled and the line resolves to a catalog product. Without both, availability marks are absent, which means not evaluated rather than unavailable. A resolved product with no inventory_key reads NONE: a real answer, not an unevaluated one.
An option that can fulfill nothing is omitted. An option whose stock read failed is kept, marked UNKNOWN. The whole-cart availability is therefore FULL, PARTIAL or UNKNOWN, never NONE.
include_variationsreturns each maximal single-location variation of an option as its own entry, so a caller can compose a multi-delivery checkout.allocation_checkapplies the merchant's allocation rules on top of the stock read. It defaults to the value ofinventory_check; set it tofalsealongsideinventory_checkfor a pure stock answer.fulfillment_locationsnarrows the stock read to the named locations.- A radius-covered location is only eligible when
customer.coordsis supplied. - An item that an option's
item_product_categoriescondition excludes is markedNONEin every entry of that option, whether or not stock was read.
Collection points
Each COLLECTION option lists its eligible collection points. An option configured with an explicit list offers exactly those; one with no list offers every active collection location in customer.country. With customer.coords, points are sorted nearest first and bounded by the smaller of max_collection_distance and the option's configured maximum. The list is capped at max_collection_locations, 10 by default and 50 at most.
Errors
400— no line items.400— afulfillment_locationsentry that resolves to no location.400—allocation_checktrue withoutinventory_check.
Related: How delivery options are evaluated
Headers
| Name | Value | Required | Description |
|---|---|---|---|
| Authorization | Bearer YOUR-ACCESS-TOKEN | Yes | OAuth 2.0 bearer token obtained from `POST /oauth/token`. |
| x-api-key | YOUR-API-KEY | Yes | Your tenant's API key, issued in the Carriyo Dashboard. Required on every request except `POST /oauth/token`. |
| tenant-id | YOUR-TENANT-ID | Yes | Your Carriyo tenant ID, shown in the Carriyo Dashboard. Required on every request except `POST /oauth/token`. |
| Content-Type | application/json | Yes | Media type of the request body. |
Request body
application/jsonSchema: delivery-options-requestrequired- The sales channel the cart originates from, matching
sales_channelon the order you create afterwards. Used during stock-aware filtering to evaluate allocation rules conditioned on sales channel, so the cart sees the same rule decisions the order will. When omitted, channel-scoped allocation rules do not match. - The items in the cart; at least one is required.
weight.valueis the weight of a single unit, so a line contributesweight.valuetimesquantityto the order weight, which is compared in kilograms. A line'scategoryfalls back to the catalog product's category when omitted. - Candidate fulfillment locations, by
partner_location_code,partner_location_idorpartner_location_name. An option matches when at least one of them is in its location allowlist, or it has no allowlist. Withinventory_check, they also narrow the stock read, the returned locations and the location used for the fee and arrival estimate. - Restrict the response to options of the listed methods. When omitted or empty, all methods are returned. Useful when the storefront has separate UI tabs for delivery and click-and-collect, or when the integration only supports one method (e.g., Shopify's standard Carrier Service API has no pickup-point concept, so the Shopify connector sets this to
["DELIVERY"]).
Responses
An array of delivery-options-response-item. Each item has the following fields:
- Earliest estimated arrival date/time (ISO 8601). Absent when the option configures no delivery window, leaving
estimated_arrival_toas the only arrival value — render the estimate as a single point rather than a range. Both arrival fields are absent when the option configures no delivery estimate at all, and on an entry that failed after its fee resolved. - Eligible collection points for a
COLLECTIONoption, nearest first withcustomer.coords. An option with no configured list resolves to every active collection location in the customer's country; a configured list is not country-filtered. An option with no eligible points is omitted from the response.
Need the full machine-readable spec? Download the OpenAPI document →
/storefront/validate/phoneValidate a phone number
Validates a customer phone number and returns its parsed parts.
Behavior
Pass the number and, when the number is in national format, the country whose dialling rules apply. The call always returns 200: is_valid is always present, and country_code and national_number are omitted when the number is invalid. A blank or unparseable number returns is_valid: false.
Headers
| Name | Value | Required | Description |
|---|---|---|---|
| Authorization | Bearer YOUR-ACCESS-TOKEN | Yes | OAuth 2.0 bearer token obtained from `POST /oauth/token`. |
| x-api-key | YOUR-API-KEY | Yes | Your tenant's API key, issued in the Carriyo Dashboard. Required on every request except `POST /oauth/token`. |
| tenant-id | YOUR-TENANT-ID | Yes | Your Carriyo tenant ID, shown in the Carriyo Dashboard. Required on every request except `POST /oauth/token`. |
| Content-Type | application/json | Yes | Media type of the request body. |
Request body
application/jsonSchema: validate-phone-requestrequiredResponses
validate-phone-responseNeed the full machine-readable spec? Download the OpenAPI document →
/storefront/product-delivery-optionsGet per-product delivery options
Returns the delivery options available for each product in a list, evaluated per product from its own fulfillment location, for delivery promises on listing and product pages.
Behavior
What to send
products is required, with one to 50 entries, each naming a catalog product by product_id or product_ref and carrying between one and five fulfillment locations, its own or the request default. merchant and customer are optional. Every other field is read only when a configured condition needs it:
order_datefor working and blackout days and the estimated arrival windowcustomerfor geography, the allocation address and the arrival destinationunit_pricetimesquantity, incurrency, for order value and payment typeweightfor weightcategoryfor product anditem_product_categoriesconditionssales_channelfor allocation rules only; it does not filter options
This endpoint has no delivery_methods, payment, parcels or include_variations, and no collection-point parameters.
Products resolve to catalog products by product_ref or product_id. sku is not a lookup key. Each product's category comes from the request, then from the catalog. A product that an option's item_product_categories condition excludes has that option omitted from its delivery_options.
fulfillment_locations at the top level is the default for every product, and products[].fulfillment_locations overrides it. Reference a location by partner_location_id, partner_location_code or partner_location_name.
What comes back
Every requested product is represented, even one whose delivery_options is empty. PASS_THROUGH options are omitted from this endpoint.
Each entry is a single-delivery fact: one shipping_fee, one estimated arrival window, one availability verdict, and the fulfillment_locations that can each alone provide exactly that answer. Everything it marks available ships together in one delivery from any one of those locations; an entry never claims fulfillment across several locations.
When an option's locations differ in what they can offer, the entry reports the best of them and lists only the locations sharing that answer. Best is decided in a fixed order:
- best availability verdict
- fastest estimated arrival window
- highest
fulfillable_quantity - the option's configured location order
When stock was evaluated, entries are banded by availability, FULL first, then PARTIAL, UNKNOWN and NONE, and ordered by sort_by and sort_direction within each band. When stock was not evaluated, ordering is sort_by and sort_direction alone. With the default SPEED, the first entry is the fastest option that can deliver the full quantity, whenever stock was checked and one exists.
Shipping fee
Fees resolve as they do on the cart endpoint, with the product's unit_price times quantity standing in for the order total.
The request currency selects which of the option's pricing entries applies but does not force the currency of the answer. The entry is chosen in a fixed order:
- the entry matching the request currency
- the option's default-currency entry
- the first configured entry, only when the option has no default currency
A configured default currency that matches no entry yields an empty fee. Always render the returned shipping_fee.currency.
- An empty
shipping_feemeans no price could be resolved: no tier contained the product value, or no currency matched. It is not free shipping. - A tiered fee ending in a free tier reports that tier's
min_valueasfree_shipping_threshold, independent of the product value, and it stays present even when the fee amount could not be resolved.
Stock (inventory_check)
The stock check runs only when inventory management is enabled and the product resolves to a catalog product. Without both, availability and fulfillable_quantity are absent, which means not evaluated rather than unavailable. A resolved product with no inventory_key reads NONE with fulfillable_quantity 0: a real answer, not an unevaluated one.
Each entry carries an availability verdict (FULL, PARTIAL or NONE against the requested quantity) and a fulfillable_quantity capped at the requested quantity.
An option that can fulfill nothing is kept, marked NONE with fulfillable_quantity 0. An option whose stock read failed is kept, marked UNKNOWN, with no fulfillable_quantity. An option is absent only when it does not match the product or serves none of the product's fulfillment locations.
allocation_checkapplies the merchant's allocation rules on top of the stock read. It defaults to the value ofinventory_check; set it tofalsealongsideinventory_checkfor a pure stock answer.- Availability honors each location's fulfillment coverage: a location outside its zones or radius can only appear on entries marked
NONE. - A radius-covered location is only eligible when
customer.coordsis supplied.
Products not in the catalog
A product_id or product_ref that matches no product does not fail the request. The product keeps its place as an error row with delivery_options empty and error.code PRODUCT_NOT_FOUND; the row echoes the identifier you sent and omits product_id when it could not be resolved. An error row carries no availability, so treat it as not evaluated, never as out of stock. Only request-level problems fail the whole call.
Errors
400— no products, or more than 50.400— a product withoutproduct_idorproduct_ref.400— a product requested twice.400— aquantitybelow 1.400— a product with no fulfillment location, or more than 5.400— a location reference resolving to nothing, or to an inactive or non-fulfillment location.400—allocation_checktrue withoutinventory_check.
Related: How products, identifiers and inventory keys fit together
Headers
| Name | Value | Required | Description |
|---|---|---|---|
| Authorization | Bearer YOUR-ACCESS-TOKEN | Yes | OAuth 2.0 bearer token obtained from `POST /oauth/token`. |
| x-api-key | YOUR-API-KEY | Yes | Your tenant's API key, issued in the Carriyo Dashboard. Required on every request except `POST /oauth/token`. |
| tenant-id | YOUR-TENANT-ID | Yes | Your Carriyo tenant ID, shown in the Carriyo Dashboard. Required on every request except `POST /oauth/token`. |
| Content-Type | application/json | Yes | Media type of the request body. |
Request body
application/jsonSchema: product-delivery-options-requestrequiredResponses
product-delivery-options-responseAn array of product-delivery-result. Each item has the following fields:
- The options for this product, always an array. When stock was evaluated, entries are banded
FULL,PARTIAL,UNKNOWN,NONE, withsort_byandsort_directionapplied within each band. Empty when nothing matches or the product is not in the catalog (seeerror); an out-of-stock option appears markedNONErather than being dropped.
Need the full machine-readable spec? Download the OpenAPI document →
/storefront/locationsGet eligible locations
Returns the active locations that can serve a customer, nearest first when coordinates are supplied, so you can choose where to fulfill from or which collection points to offer.
Behavior
What to send
merchant and customer.country are required. customer.coords is optional and unlocks distance, nearest-first order and max_distance.
Eligibility
A location qualifies when it is active, the merchant has access to it and it carries the requested function. Geography is then checked by function:
FULFILLMENTlocations are gated by their coverage. Zones qualify a location when they cover the customer's country, state, city or area. A radius needs coordinates on both sides, so a radius-covered location without coordinates, or a request withoutcustomer.coords, is ineligible. A location with neither serves everywhere.COLLECTIONlocations qualify on their collection flag alone. The only geographic constraint ismax_distance.
Distance and order
With customer.coords, each location carries a distance and the list is nearest first; locations with no computable distance come last. Without coordinates the list is in location_code order. max_distance caps how far out to look and needs coordinates.
Filters
functions accepts FULFILLMENT and COLLECTION and defaults to FULFILLMENT. location_type filters by STORE or WAREHOUSE.
Cap
The call returns the complete answer capped at max_locations (default 10, maximum 50), with no paging. Receiving exactly max_locations items means more may exist, so narrow the filters or raise the cap.
Errors
400—merchantmissing.400—customer.countrymissing.400—max_distancewithoutcustomer.coords.400—max_locationsoutside 1 to 50.400—page,page_size,sort_byorsort_directionsupplied.
Headers
| Name | Value | Required | Description |
|---|---|---|---|
| Authorization | Bearer YOUR-ACCESS-TOKEN | Yes | OAuth 2.0 bearer token obtained from `POST /oauth/token`. |
| x-api-key | YOUR-API-KEY | Yes | Your tenant's API key, issued in the Carriyo Dashboard. Required on every request except `POST /oauth/token`. |
| tenant-id | YOUR-TENANT-ID | Yes | Your Carriyo tenant ID, shown in the Carriyo Dashboard. Required on every request except `POST /oauth/token`. |
| Content-Type | application/json | Yes | Media type of the request body. |
Request body
application/jsonSchema: eligible-locations-requestrequired- Cap on returned locations. The response is one complete, capped answer in fixed selection order (nearest-first with
customer.coords,location_codeorder otherwise) — there are no pages. Receiving exactlymax_locationsitems means more may exist; narrow the filters or raise the cap.
Responses
eligible-locations-responseAn array of eligible-location. Each item has the following fields:
Need the full machine-readable spec? Download the OpenAPI document →