API reference

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.

Serverhttps://api.carriyo.comAuthOAuth 2.0 + API KeySpecstorefront.yaml

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.

4 operations · 0 objects

post/storefront/delivery-options

Get delivery options

Returns the delivery options that match the supplied cart or order details at checkout time.

Delivery options are configured per merchant in the Carriyo Dashboard. Each option declares the carrier account that fulfils it, a shipping fee, an estimated delivery window, and a set of optional conditions. This endpoint evaluates the configured conditions against the order details you supply inline and returns the matching options, typically rendered to the shopper as the delivery choices on the checkout page.

Both DELIVERY and COLLECTION options can be returned. The shopper has not chosen between them at this point, so customer represents where the customer is, not where the order is being delivered. For DELIVERY options the customer's location is also the delivery destination; for COLLECTION options it's used to find applicable collection points.

Supplying order details

Pass the order details inline in the request body. merchant and line_items (with at least one item) are required; a request without line items is rejected with a 400. Populate the remaining fields based on which conditions the merchant has configured. This endpoint does not look up existing orders; all order data must be provided directly in the request.

Restricting by delivery method

Pass delivery_methods to limit the response to only the methods you can render. For example, send ["DELIVERY"] from a storefront that doesn't support pickup points, or ["COLLECTION"] from a click-and-collect locator screen. Omit the field to receive all matching methods.

What gets evaluated

Each condition only applies when the merchant has configured it on a delivery option. The corresponding order field is read only if such a condition exists, so callers only need to populate the fields relevant to the rules in use.

| Condition (configured on the option) | Evaluated against |

|---|---|

| Working days / blackout days | order_date (defaults to now); timezone derived from customer.country |

| Customer geography | customer.{country, state, city, area} |

| Order value range | payment.order_total |

| Weight range | Total order weight: sum of line_items[].weight × quantity (converted to kg) |

| Payment type | Derived from payment.payment_on_delivery: CASH_ON_DELIVERY when it is greater than 0, otherwise PRE_PAID |

| Product categories | The line-item categories in the cart, judged for the whole order. Each category is resolved request-first (line_items[].category), then from the product catalog by product_id. An includes rule matches when at least one line item has a listed category; an excludes rule matches when no line item has one. Matching is case-insensitive |

| Item product categories | The same categories, judged per line item: instead of showing or hiding the option, the condition scopes which items the option can deliver (see Item-level category scoping below) |

| Fulfillment location | fulfillment_locations[]. Pass one or more candidate fulfillment locations. An option matches if at least one of the supplied locations is in the option's allowlist (or the option has no allowlist). For a configured Carriyo location, supply either partner_location_code (your own code, recommended for storefront integrations) or partner_location_id (Carriyo's internal ID); free-form address fields are also accepted |

Item-level category scoping

An option configured with item_product_categories applies per item, not to the whole order. With includes, the option applies only to items whose category is listed; with excludes, items with a listed category are excluded and every other item qualifies. An item with no category fails a non-empty includes list and passes an excludes-only condition; matching is case-insensitive and ignores surrounding whitespace.

Excluded items are marked availability: NONE with fulfillable_quantity: 0 in every entry of the option — even when stock-aware filtering is not effective. A condition exclusion is an evaluation, so it is the one exception to "absent means not evaluated": the mark appears without any stock read, and it overrides UNKNOWN. Excluded items count toward the entry's verdict — a scoped option on a mixed cart reads PARTIAL — and an option whose condition excludes every cart item is not returned at all.

Sorting the results

Results are always availability-banded first. Entries that can provide the whole cart (availability: FULL — or, when stock isn't evaluated, entries listing every line item) come before the rest; within the partial band, entries are ordered by how many line items they can at least partly provide (most first). This keeps the choices a shopper can fully order at the top.

Within each band, sort_by orders the entries:

  • SPEED (default): earliest estimated_arrival_to first.

  • COST: lowest shipping fee first.

Shipping fee resolution

Each returned option carries a shipping_fee computed from its configured pricing strategy:

  • FREE_OF_COST: always amount: 0, in the option's default currency when one is configured.

  • PAID: resolved from the option's pricing configuration. Carriyo picks the pricing entry matching payment.currency, falling back to the entry matching the option's default currency (or to the first configured entry when no default currency is set). A FIXED_PRICE option returns that entry's amount; a TIERED_ORDER_VALUE option returns the amount of the first tier whose range contains payment.order_total.

  • PASS_THROUGH: a live carrier rate quote from the option's carrier account, computed from the supplied order details (parcels and the extended line-item fields). An option saved as PASS_THROUGH without a carrier account is downgraded to FREE_OF_COST at save time, so it never reaches this endpoint as PASS_THROUGH.

A TIERED_ORDER_VALUE fee whose final, unbounded tier charges 0 also reports that tier's min_value as free_shipping_threshold — the order value at and above which the option ships free. To offer "free shipping above X", configure exactly that shape: a tiered fee ending in a free tier. A separate free option gated by an order-value condition cannot report a threshold. The threshold is derived from the matched pricing configuration, not from the cart, so it is returned regardless of the current order value.

In edge cases an option is returned with an empty shipping_fee ({}): when a TIERED_ORDER_VALUE fee finds no tier containing the order total (or the request omits payment.order_total), when a default currency is configured but neither it nor payment.currency matches any pricing entry, or when a PASS_THROUGH rate lookup fails (for example, the carrier account no longer exists). Treat a fee without an amount as "no price available", not as free shipping. In the first case the matched tier table still derives its free_shipping_threshold, so the fee may carry free_shipping_threshold with no amount or currency — which is exactly what an "add X more for free shipping" prompt needs when the cart value is not yet known. When no pricing entry matched at all, there is no table to derive from and the fee is truly empty.

Fees are always evaluated against the request as supplied: a TIERED_ORDER_VALUE fee on a PARTIAL entry is still looked up against the cart's payment.order_total, not the value of the entry's available subset. For exact per-consignment fees, requote each chosen subset with its own payment.

A failure while computing an option's fee drops that option from the response — a missing fee would read as free shipping downstream. A failure after the fee resolves (for example, in the arrival estimate) fails open instead: the option is returned with its shipping_fee, no arrival estimate, and availability: UNKNOWN when stock was being evaluated.

Collection points for COLLECTION options

For each matching COLLECTION option, Carriyo also returns a list of eligible collection points (configured Carriyo locations with the collection_location flag enabled) under customer_collection_locations on the response item.

The candidate set comes from the option's configuration. An option that links an explicit list of collection locations offers exactly those locations (filtered to ACTIVE, collection-enabled ones). An option with an empty or omitted list means any location: it resolves to every ACTIVE collection-enabled location the merchant can use, restricted to the customer's country (customer.country). If nothing resolves — for example, no collection-enabled location exists in the customer's country — the option is omitted from the response.

The country semantics differ deliberately between the two configurations. The any-location behaviour is always same-country: customers collect where they are, so Carriyo bounds the resolved set to customer.country. An explicit list is not country-filtered — it is the merchant's deliberate selection, and may include cross-border collection points (for example, a store just across a border from the customer's city); the distance cap, when in effect, is a proximity bound rather than a country bound. Note this contrasts with fulfillment_locations, where an empty list means any fulfilling location regardless of country — fulfillment can legitimately be cross-border, and each fulfillment location carries its own configurable coverage (zones or radius).

Three pieces of input then shape the result:

  • customer.coords: when supplied (latitude/longitude), Carriyo computes the distance from the customer to each location and sorts the result nearest-first. Locations without coordinates are excluded from a distance-bound result. When customer coordinates aren't supplied, locations are returned in the merchant-configured order (location-code order for options without a configured list) with no distance field.

  • max_collection_distance (request): a client-supplied upper bound on the returned distance. Effective only when customer coordinates are supplied.

  • customer_collection_max_distance (per-option, configured by the merchant): a hard upper bound the merchant authored for this option. Carriyo applies the smaller of this and the request's max_collection_distance when filtering.

The result list is capped at max_collection_locations (defaults to 10 when omitted, capped server-side at 50).

Stock-aware filtering

Set inventory_check to true to evaluate delivery options against real-time stock. The check is effective only when all of the following hold:

  1. inventory_check is true in the request.

  2. Inventory management is enabled for the tenant in Carriyo settings.

  3. The line items carry a product_id, or a product_ref that resolves to one (see line_items).

When effective, every entry in the response is a single-delivery fact: the items it marks as available are deliverable together in one delivery, from any one of the entry's fulfillment_locations, at the entry's shipping_fee. No entry ever claims fulfilment across several locations; composing a multi-delivery checkout is the caller's explicit act (see include_variations below).

Each entry carries:

  • items — every cart line item, each marked with an availability (FULL, PARTIAL, NONE, or UNKNOWN) and, when evaluated, the fulfillable_quantity this entry can provide. Items the entry cannot supply are listed as NONE, not dropped.

  • fulfillment_locations — the locations this entry can be fulfilled from, as {partner_location_id, partner_location_code, partner_location_name} objects. Each listed location can on its own fulfil everything the entry marks as available.

  • availability — the entry's verdict for the whole cart: FULL, PARTIAL, or UNKNOWN.

An absent availability field — at any level — always means not evaluated (the stock check is off, or a line has no resolvable product), never "unavailable". UNKNOWN means the check ran and failed to answer: treat it as "no answer", never as out of stock. The one mark that appears without a stock read is the NONE forced by an option's item_product_categories condition (see Item-level category scoping above).

When the request supplies fulfillment_locations, they narrow the whole evaluation: the stock read, the returned fulfillment_locations lists, and the location used for the fee and arrival estimate all consider only the requested locations. Pass a single location and an option's presence means that location can serve this cart.

Location eligibility honors each location's fulfillment coverage, the same zone and radius gating described in Get eligible locations. Radius coverage is matched by distance, so it needs customer.coords in the request. Without customer coordinates, a radius-covered location is never eligible and its stock is invisible to this endpoint. Pass customer coordinates whenever the merchant fulfills from radius-covered locations.

Delivery options that cannot fulfill any of the requested items are omitted entirely from the response — unless an item's inventory read failed, in which case the option is returned marked UNKNOWN rather than hidden.

When stock-aware filtering is not effective (inventory_check is false or omitted, inventory management is disabled, or no product_id is supplied), the endpoint does not evaluate stock:

  • items echoes back all request line items, carrying no availability marks (not evaluated) — except items excluded by the option's item_product_categories condition, which are still marked NONE with fulfillable_quantity: 0.

  • fulfillment_locations returns the option's configured fulfillment locations as {partner_location_id, partner_location_code, partner_location_name} objects (or is omitted if none are configured).

Cart splitting (include_variations)

By default each option appears at most once: the entry with the best coverage (most fully covered items, then most covered quantity, then the option's configured location order). When no single location can supply the whole cart, that best entry is PARTIAL — the response never silently promises a split delivery.

Set include_variations to true to receive every maximal single-delivery variation of each option as its own entry — same code, different items marks and fulfillment_locations. Entries whose coverage is contained in another entry's are dropped, so the response is bounded at one entry per candidate location. Entries sharing a code are distinct single-delivery alternatives of the same option, not duplicates: pick one, or compose several into a multi-delivery checkout, requoting each chosen subset for its exact fee.

Routing-rules preview (allocation_check)

allocation_check controls whether the merchant's order-allocation routing rules are applied on top of the stock read. It defaults to the value of inventory_check, so omitting it changes nothing. Set it to false alongside inventory_check: true for a pure stock answer with no routing policy applied. Setting it to true without inventory_check is rejected with a 400 — the rules operate on the stock table, so the combination has no meaning.

Response

An array of single-delivery entries, each with its carrier account, computed shipping fee, and estimated arrival window, availability-banded then ordered by sort_by. By default each matching option appears once; with include_variations: true an option can appear several times (same code, different items and fulfillment_locations). The array is empty if no configured option matches the supplied order.

Headers

NameValueRequiredDescription
AuthorizationBearer YOUR-ACCESS-TOKENYesOAuth 2.0 bearer token obtained from `POST /oauth/token`.
x-api-keyYOUR-API-KEYYesYour tenant's API key, issued in the Carriyo Dashboard. Required on every request except `POST /oauth/token`.
tenant-idYOUR-TENANT-IDYesYour Carriyo tenant ID, shown in the Carriyo Dashboard. Required on every request except `POST /oauth/token`.
Content-Typeapplication/jsonYesMedia type of the request body.

Request body

Content type: application/jsonSchema: delivery-options-requestrequired
  • merchantstringrequired
    The merchant the order belongs to. The API key must have access to this merchant.
  • sales_channelstring
    The sales channel the cart originates from, matching sales_channel on 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.
  • order_datestringformat: date-time
    The date the order was placed (ISO 8601). Defaults to the time of the request. Used as the reference date for working-day and blackout-day evaluation.
  • paymentdelivery-options-payment
    Payment details for the order. Drives order_value and payment_type conditions.
  • line_itemsdelivery-options-line-item[]required
    The items in the order. At least one item is required. weight.value is the weight of a single unit; the total weight for a line is weight.value × quantity. The total order weight used for weight range conditions is the sum of those per-line totals, converted to kg. Identify each line with product_id or product_ref to make stock-aware filtering effective (see inventory_check). Set category to drive product-category conditions; when omitted, the category comes from the resolved catalog product.
  • parcelsdelivery-options-parcel[]
    Parcels in the order. Used by the carrier rate calculator when a matching option's pricing strategy is PASS_THROUGH (i.e., the carrier-quoted rate is shown to the shopper). Not used by condition matching; weight conditions are evaluated against line_items.
  • fulfillment_locationsdelivery-options-address[]
    Candidate locations the order could be fulfilled from (origin/warehouse/store). Pass one or more, and Carriyo returns the options whose fulfillment-location allowlist contains at least one of these (options without an allowlist are unconstrained). Per option, the first matching location is used to drive origin-country-based estimated arrival and, for PASS_THROUGH pricing, the carrier rate quote. Each entry may be a free-form address, or, for a configured Carriyo location, supply partner_location_code (your own code, recommended) or partner_location_id (Carriyo's internal ID), and the rest of the address is populated from the location record. An entry referencing a location that does not exist (e.g. a typo'd code) is rejected with a 400 naming the offending entry. When stock-aware filtering is effective (see inventory_check), the supplied locations narrow everything: which options match, which locations the stock evaluation considers, and the location lists in the response. Pass a single location and an option's presence means that location can serve this cart.
  • customerdelivery-options-address
    The customer's location. Drives customer-geography conditions and the timezone used for working-day / blackout-day evaluation. Strongly recommended for any non-trivial result. For DELIVERY options this is also the implicit delivery destination. For COLLECTION options it's used to find applicable collection points. The shopper has not chosen between the two at this stage; the field captures where the customer is, not where the order is being delivered.
  • inventory_checkboolean
    Set to true to filter options by real-time stock. Effective only when inventory management is enabled for the tenant and the line items carry (or resolve to) a product_id. When not effective, no stock filtering is applied.
  • allocation_checkboolean
    Whether the merchant's order-allocation routing rules are applied on top of the stock read. Defaults to the value of inventory_check, so omitting it changes nothing. Set to false alongside inventory_check: true for a pure stock answer with no routing policy applied. true without inventory_check: true is rejected with a 400.
  • include_variationsboolean
    Set to true to return every maximal single-delivery variation of each option as its own entry — same code, different items marks and fulfillment_locations — instead of only the best-coverage entry per option. Entries sharing a code are distinct single-delivery alternatives of the same option: pick one, or compose several into a multi-delivery checkout, requoting each chosen subset for its exact fee. Meaningful only when stock-aware filtering is effective (see inventory_check); otherwise each option yields a single entry anyway.
  • sort_bystring
    Orders the entries within each availability band. SPEED (default) puts the earliest estimated_arrival_to first; COST puts the lowest shipping fee first. Entries are always availability-banded before this ordering is applied.
    Values:SPEEDCOST
  • sort_directionstring
    Direction applied to sort_by. ASC (default) orders soonest/cheapest first; DESC reverses the non-null ordering. Options with no arrival estimate or fee always sort last regardless of direction.
    Values:ASCDESC
  • delivery_methodsstring[]
    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"]).
  • max_collection_locationsinteger
    Maximum number of customer collection locations to return per matching COLLECTION option. Defaults to 10 when omitted; capped server-side at 50. Ignored for DELIVERY and DIGITAL options.
  • max_collection_distancedistance
    Client-supplied upper bound on the distance from the customer's location to a returned collection point. The effective cap used by Carriyo is the smaller of this value and any per-option customer_collection_max_distance configured by the merchant. When the customer's coordinates aren't supplied, this cap can't be enforced and is ignored.

Responses

200The delivery options that match the supplied order.

An array of delivery-options-response-item. Each item has the following fields:

  • idstring
    Unique identifier for this delivery option.
  • delivery_methodstring
    The fulfilment method for this option: - DELIVERY: courier delivers to the customer's address. - COLLECTION: customer collects from a designated location. - DIGITAL: no physical fulfilment. Aligns with FulfillmentOrder.delivery_method on the order model.
    Values:COLLECTIONDELIVERYDIGITAL
  • codestring
    The merchant-defined code identifying the delivery option.
  • namestring
    Display name of the delivery option (shown to the shopper).
  • descriptionstring
  • image_urlstring
    URL to an icon or image associated with the option.
  • carrier_account_idstring
    The Carriyo carrier account that fulfils this option.
  • shipping_feedelivery-options-shipping-fee
    The shipping fee computed for the option. In edge cases it is returned empty ({}), or with only free_shipping_threshold — see "Shipping fee resolution" on Get delivery options. Treat a fee without an amount as "no price available", not as free shipping.
  • estimated_arrival_fromstringformat: date-time
    Earliest estimated arrival date/time (ISO 8601). Absent when the option configures no delivery window, leaving estimated_arrival_to as 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.
  • estimated_arrival_tostringformat: date-time
    Latest estimated arrival date/time (ISO 8601). Absent when the option configures no delivery estimate, in which case estimated_arrival_from is absent too.
  • itemsdelivery-option-line-item-ref[]
    Every line item from the request, each marked with what this entry can provide of it and keyed by line_item_id (the line's id, or the one Carriyo assigned when you omitted it — see line_items[].id). When stock-aware filtering is effective (inventory_check is true, inventory management is enabled, and the line items carry product_id), each item carries an availability (FULL, PARTIAL, NONE, or UNKNOWN) and, when evaluated, a fulfillable_quantity for this entry. Items the entry cannot supply are listed as NONE, not dropped; the marked items are deliverable together in one delivery from any one of the entry's fulfillment_locations. When stock-aware filtering is not effective, all request line items are returned here with no availability marks — absence means "not evaluated", never unavailable. Items excluded by the option's item_product_categories condition are the exception: they are marked NONE with fulfillable_quantity: 0 in every entry, stock read or not. An option that can provide none of the items is omitted from the response entirely (unless the answer is unknown — see availability), so a returned entry always lists at least one line item.
  • fulfillment_locationsresolved-fulfillment-location[]
    The locations this entry can be fulfilled from, each as a {partner_location_id, partner_location_code, partner_location_name} object. When stock-aware filtering is effective, each listed location can on its own fulfil everything this entry marks as available — the entry is a single delivery from any one of them. Locations that can only cover a different subset of the cart surface as separate entries (see include_variations); the list is never a union of partially-capable locations. When stock-aware filtering is not effective, this returns the option's configured fulfillment locations. Omitted (null) if the option has no configured fulfillment locations.
  • availabilitystring
    This entry's verdict for the whole cart: FULL when every line item is fully available from this entry, PARTIAL when some aren't, UNKNOWN when any line's inventory read failed (the cart-level answer is unknowable — treat as "no answer", never as out of stock). Lines that were never evaluated (no resolvable product) don't count against the verdict; lines excluded by the option's item_product_categories condition do — they are NONE, so a scoped option on a mixed cart reads PARTIAL, even when stock-aware filtering is not effective. Otherwise absent when stock-aware filtering was not effective — absence means "not evaluated", never unavailable. An option that fails while being assembled after its fee resolved is returned as a minimal entry — availability: UNKNOWN (when stock was being evaluated), its shipping_fee, and no arrival estimate — rather than dropped.
    Values:FULLPARTIALUNKNOWN
  • customer_collection_locationscustomer-collection-location[]
    Eligible collection points for this option. Populated only when delivery_method is COLLECTION. Sorted nearest-first when the customer's coordinates are supplied; otherwise returned in the merchant-configured order (location-code order for options without a configured list). An option configured without a location list resolves to any ACTIVE collection-enabled location in the customer's country. COLLECTION options with no resolvable collection points (none configured and eligible, or none within the effective distance cap) are omitted from the response entirely.
400The request failed validation. Returned when `line_items` is missing or empty (without line items no delivery option can be matched to the cart), when `allocation_check` is `true` without `inventory_check: true`, or when a `fulfillment_locations` entry references a location that cannot be resolved — the error message names the offending entry, e.g. `fulfillment_locations[1] ('XYZ') does not match any location.`

Need the full machine-readable spec? Download the OpenAPI document →

post/storefront/validate/phone

Validate a phone number

Validates a customer phone number and returns its parsed parts.

Carriyo parses the number with libphonenumber. Pass the number and, when the number is in national format, the country whose dialling rules apply. Use this at checkout to catch a mistyped number before the shopper places the order.

Headers

NameValueRequiredDescription
AuthorizationBearer YOUR-ACCESS-TOKENYesOAuth 2.0 bearer token obtained from `POST /oauth/token`.
x-api-keyYOUR-API-KEYYesYour tenant's API key, issued in the Carriyo Dashboard. Required on every request except `POST /oauth/token`.
tenant-idYOUR-TENANT-IDYesYour Carriyo tenant ID, shown in the Carriyo Dashboard. Required on every request except `POST /oauth/token`.
Content-Typeapplication/jsonYesMedia type of the request body.

Request body

Content type: application/jsonSchema: validate-phone-requestrequired
  • phone_numberstringrequired
    The phone number to validate. Accepts E.164 (+<country><number>) or national format.
  • countrystring
    Two-letter ISO 3166-1 alpha-2 country code. Used to parse a national-format phone_number; not needed when the number is in E.164 format.

Responses

200The parsed phone number and whether it is valid.Schema: validate-phone-response
  • is_validboolean
    Whether the number is a valid, dialable number. Always present.
  • national_numberstring
    The number in national format, without the country dialling code. Present when the number parsed.
  • country_codestring
    Echoes the country supplied in the request. Present when a country was provided (omitted for an E.164 number sent without a country).
  • raw_inputstring
    The phone_number exactly as supplied in the request. Always present.

Need the full machine-readable spec? Download the OpenAPI document →

post/storefront/product-delivery-options

Get per-product delivery options

Returns the delivery options available for each product in a list, so you can show a delivery promise (for example "Get it in 45 minutes") on a product listing or product detail page.

Unlike Get delivery options, which evaluates one cart as a whole, this endpoint evaluates each product on its own from its own fulfillment location. Send the products and the location each one ships from; Carriyo returns the matching delivery options per product.

Choosing the fulfillment location

Set fulfillment_locations at the top level as the default for every product, and override it per product under products[].fulfillment_locations. Reference a configured Carriyo location by partner_location_id or partner_location_code. To find the nearest eligible locations for a customer first, call Get eligible locations.

Category and value

Each product's category is resolved request-first (products[].category), then from the catalog entry the product resolved to. The product's value is unit_price × quantity. Both feed the same option conditions as the cart endpoint. An option whose item_product_categories condition excludes the product's category is omitted from that product's delivery_options — the per-product counterpart of the cart endpoint marking the item NONE. Options priced PASS_THROUGH (a live carrier quote) are omitted from this endpoint.

Shipping fee

Fees resolve exactly as they do on the cart endpoint — see "Shipping fee resolution" on Get delivery options — with the product's unit_price × quantity standing in for the cart's order total, and PASS_THROUGH options excluded before pricing runs.

The request currency selects which of the option's configured pricing entries applies; it does not force the currency of the answer. When no entry matches, Carriyo falls back to the option's default-currency entry, then to its first configured entry — so shipping_fee.currency can differ from the currency you sent. Always render the returned currency, never the requested one. An option that resolves no fee at all returns an empty shipping_fee ({}); treat that as "no price available", not as free shipping.

free_shipping_threshold carries over from the cart endpoint unchanged: a tiered fee whose final, unbounded tier charges 0 reports that tier's min_value as the order value at and above which the option ships free. It is derived from the matched pricing configuration, not from this product's value, and stays present even on an entry whose fee amount could not be resolved.

Stock

Set inventory_check to true to mark each delivery-option entry with an availability verdict (FULL, PARTIAL, or NONE against the requested quantity) and a fulfillable_quantity capped at the requested quantity. It is effective only when inventory management is enabled for the tenant. Absolute stock counts are never returned — the verdict and the request-capped quantity are the whole answer.

A product with no stock anywhere still returns its eligible options, each marked availability: NONE with fulfillable_quantity: 0 — options are never dropped for being out of stock. An option is absent from a product's delivery_options only when it does not match the product (conditions, item_product_categories) or serves none of the product's fulfillment locations.

When the check is effective, availability also honors each location's fulfillment coverage (zones or radius, as described in Get eligible locations). A location outside coverage has no stock to offer, so it can only appear on entries marked NONE. Radius coverage is matched by distance, so it needs customer.coords: pass customer coordinates when working with radius-covered locations.

allocation_check controls whether the merchant's order-allocation routing rules are applied on top of the stock read. It defaults to the value of inventory_check, so omitting it changes nothing. Set it to false alongside inventory_check: true for a pure stock answer with no routing policy applied; true without inventory_check is rejected with a 400.

If the stock read fails, the endpoint never fails closed: entries are returned as if no stock check ran (no fulfillable_quantity, delivery options evaluated normally), marked with availability: UNKNOWN — treat that as unknown, never as out of stock.

Limits

  • At most 50 products per request.

  • At most 5 fulfillment locations per product.

  • A product may not be requested twice.

Response

A bare array, one object per requested product: the resolved product_id, your product_ref when you supplied one, the requested quantity, and its delivery_options. Each eligible option appears exactly once per product, as a single-delivery fact mirroring the cart endpoint's contract: the option's display fields and shipping_fee, one delivery window, one availability verdict with its fulfillable_quantity, and the fulfillment_locations that can each alone provide exactly that availability and window.

When an option's locations differ in what they can offer, its entry reports the best of them — best availability verdict, then fastest delivery window, then highest fulfillable quantity, then the option's configured location order — and lists only the locations sharing that best answer. The selection is deterministic.

Each product's delivery_options is availability-banded when stock was evaluated — FULL entries first, then PARTIAL, then UNKNOWN, then NONE — with sort_by / sort_direction applied within each band. When inventory was not evaluated, ordering is pure sort_by / sort_direction. With the default SPEED, delivery_options[0] is the product's fastest deliverable option whenever stock was checked — the PLP read. (Filter on availability only if you also want to exclude PARTIAL entries.) Products whose delivery_options is empty (no option matches) are kept, so every requested product is represented.

Headers

NameValueRequiredDescription
AuthorizationBearer YOUR-ACCESS-TOKENYesOAuth 2.0 bearer token obtained from `POST /oauth/token`.
x-api-keyYOUR-API-KEYYesYour tenant's API key, issued in the Carriyo Dashboard. Required on every request except `POST /oauth/token`.
tenant-idYOUR-TENANT-IDYesYour Carriyo tenant ID, shown in the Carriyo Dashboard. Required on every request except `POST /oauth/token`.
Content-Typeapplication/jsonYesMedia type of the request body.

Request body

Content type: application/jsonSchema: product-delivery-options-requestrequired
  • merchantstringrequired
    The merchant the products belong to. The API key must have access to this merchant.
  • sales_channelstring
    The sales channel the storefront request originates from, matching sales_channel on orders you create afterwards. Used during stock-aware filtering to evaluate allocation rules conditioned on sales channel. When omitted, channel-scoped allocation rules do not match.
  • order_datestringformat: date-time
    Reference date for working-day and blackout-day evaluation (ISO 8601). Defaults to the time of the request.
  • currencystring
    ISO 4217 three-letter currency code for the supplied unit_price values. It also selects which of an option's configured pricing entries applies, but does not force the currency of the returned fee — read shipping_fee.currency for that.
  • customerdelivery-options-address
    The customer's location. Drives customer-geography conditions and the timezone for working-day evaluation. Supply coords to drive distance-based option logic.
  • inventory_checkboolean
    Set to true to mark each delivery-option entry with an availability verdict and a fulfillable_quantity. Effective only when inventory management is enabled for the tenant.
  • allocation_checkboolean
    Whether the merchant's order-allocation routing rules are applied on top of the stock read. Defaults to the value of inventory_check, so omitting it changes nothing. Set to false alongside inventory_check: true for a pure stock answer with no routing policy applied. true without inventory_check: true is rejected with a 400.
  • fulfillment_locationslocation-request[]
    Default fulfillment locations applied to every product. Reference a configured Carriyo location by partner_location_id or partner_location_code. Override per product under products[].fulfillment_locations. Required for any product that does not carry its own override: a product with no effective fulfillment location is rejected with a 400.
  • productsproduct-delivery-options-product[]required
    The products to evaluate. Between 1 and 50. The same product may not be requested twice, whether by a repeated identifier or by two identifiers resolving to it.
  • sort_bystring
    Orders each product's delivery_options. SPEED by earliest arrival, COST by lowest fee.
    Values:SPEEDCOST
  • sort_directionstring
    Sort direction applied to sort_by.
    Values:ASCDESC

Responses

200The delivery options available for each product.Schema: product-delivery-options-response

An array of product-delivery-result. Each item has the following fields:

  • product_idstringrequired
    Carriyo's internal product id, resolved from whichever identifier you sent
  • product_refstring
    Your product reference, echoed back when the request supplied one
  • quantityintegerrequired
    The quantity requested for this product, echoed from the request.
  • delivery_optionsproduct-delivery-option-entry[]required
    The delivery options for this product, one entry per option. When availability was evaluated, entries are banded FULLPARTIALUNKNOWNNONE with sort_by / sort_direction applied within each band; otherwise ordered purely by sort_by / sort_direction. Always an array: [] when no option matches the product, never null and never omitted. An out-of-stock option is not dropped — it appears marked availability: NONE.
400The request failed validation. Returned when `products` is empty or has more than 50 entries, a product carries neither `product_id` nor `product_ref`, a `product_ref` matches no product, the same product is requested twice (a repeated identifier, or two identifiers resolving to one product), a `quantity` is less than 1, `allocation_check` is `true` without `inventory_check: true`, a product resolves to no fulfillment locations or more than 5, or a referenced fulfillment location cannot be found or is not an active fulfillment location (a collection-only location is rejected).

Need the full machine-readable spec? Download the OpenAPI document →

post/storefront/locations

Get eligible locations

Returns the configured Carriyo locations that can serve a customer, so you can find the nearest store or warehouse to fulfill from or offer for collection.

A location is eligible when it is active, the merchant has access to it, and it carries the requested functions flag. How its geography is checked then depends on the function:

  • FULFILLMENT locations are gated by their configured coverage. Zone coverage (fulfillment_zones) qualifies a location when its zones cover the customer's country, state, city, or area terms. Radius coverage (fulfillment_radius) qualifies it when the customer is within the radius; this needs coordinates on both sides, so a location with radius coverage but no coordinates, or a request with no customer.coords, is ineligible. A fulfillment location with neither zones nor radius serves everywhere.

  • COLLECTION locations are not gated by zones or radius. A location qualifies on its collection flag alone; the only geographic constraint is max_distance, which caps how far a pickup point can be from the customer.

Distance and selection order

Supply customer.coords to get a distance on each location and nearest-first selection. The order is fixed: nearest-first when coordinates are supplied, location_code order otherwise; locations with no computable distance select last. Use max_distance (needs coordinates) to cap how far out to look.

Filtering and the cap

Filter by location_type (STORE or WAREHOUSE) and by functions (FULFILLMENT, COLLECTION; defaults to [FULFILLMENT]). One call returns the complete answer, capped by max_locations (default 10, maximum 50) — there are no pages and no way to fetch "the rest"; receiving exactly max_locations items means more may exist, so narrow the filters or raise the cap. page/page_size and sort_by/sort_direction are rejected with 400.

Headers

NameValueRequiredDescription
AuthorizationBearer YOUR-ACCESS-TOKENYesOAuth 2.0 bearer token obtained from `POST /oauth/token`.
x-api-keyYOUR-API-KEYYesYour tenant's API key, issued in the Carriyo Dashboard. Required on every request except `POST /oauth/token`.
tenant-idYOUR-TENANT-IDYesYour Carriyo tenant ID, shown in the Carriyo Dashboard. Required on every request except `POST /oauth/token`.
Content-Typeapplication/jsonYesMedia type of the request body.

Request body

Content type: application/jsonSchema: eligible-locations-requestrequired
  • merchantstringrequired
    The merchant whose locations to search. The API key must have access to this merchant.
  • functionsstring[]
    The location functions required. Defaults to [FULFILLMENT].
  • customereligible-locations-customerrequired
    The customer location used to evaluate location coverage and distance.
  • location_typestring
    Restrict to stores or warehouses. Omit to include both.
    Values:STOREWAREHOUSE
  • max_distancedistance
    Upper bound on distance from the customer. Requires customer.coords.
  • max_locationsinteger
    Cap on returned locations. The response is one complete, capped answer in fixed selection order (nearest-first with customer.coords, location_code order otherwise) — there are no pages. Receiving exactly max_locations items means more may exist; narrow the filters or raise the cap.

Responses

200The eligible locations, nearest first (with coords), capped at `max_locations`.Schema: eligible-locations-response

An array of eligible-location. Each item has the following fields:

  • location_idstring
    Carriyo's internal location identifier.
  • location_codestring
    The merchant's own location code.
  • location_namestring
  • location_typestring
    Values:STOREWAREHOUSE
  • functionsstring[]
  • custom_attributescustom-attributes
    Custom attributes in the form of a map: {"attribute1" : ["value1", "value2"], "attribute2" : ["value1", "value2"]} Please Note: You can only use custom attributes if you are subscribed to this feature.
  • address1string
  • address2string
  • citystring
  • statestring
  • countrystring
    Two-letter ISO 3166-1 alpha-2 country code.
  • postcodestring
  • areastring
  • coordsnumber[]
    Latitude and longitude as [lat, lng].
  • distancedistance
    Distance from the customer. Null when either side has no coordinates.
400The request failed validation. Returned when `customer` (with a `country`) is missing, `max_distance` is used without `customer.coords`, `max_locations` is outside 1–50, or any of the unsupported `page`/`page_size`/`sort_by`/`sort_direction` fields are sent.

Need the full machine-readable spec? Download the OpenAPI document →