Storefront API Reference¶
The Storefront API is the public-facing API that your storefront (whether server-rendered or headless) uses to interact with Merchello. It handles baskets, shipping/location preferences, currency selection, product availability, upsells, and saved payment methods.
Base URL: /api/merchello/storefront
All endpoints are anonymous by default unless noted otherwise. Responses are JSON.
Storefront Context¶
GET /context¶
Bootstrap endpoint that returns the current location, currency, and basket summary in a single call. This is perfect for initializing a headless storefront on page load.
Response:
{
"location": {
"countryCode": "GB",
"countryName": "United Kingdom",
"regionCode": null
},
"currency": {
"currencyCode": "GBP",
"currencySymbol": "\u00a3",
"decimalPlaces": 2
},
"basket": {
"itemCount": 3,
"formattedTotal": "\u00a389.97"
}
}
Tip: Use this endpoint instead of calling
/shipping/country,/currency, and/basket/countseparately. It saves you two extra HTTP round trips.
Basket Endpoints¶
POST /basket/add¶
Add a product (with optional add-ons) to the basket.
Request body:
{
"productId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
"quantity": 2,
"addons": [
{
"optionId": "...",
"choiceId": "..."
}
]
}
Response (200):
Response (400): Returned when the product is not found, out of stock, or add-on configuration is invalid.
Note: If a Google Auto Discount cookie is active and matches the product, the discount is automatically applied when the item is added.
GET /basket¶
Get the full basket with all line items and calculated totals.
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
includeAvailability |
bool | false |
Check stock availability for each line item |
countryCode |
string | null | Country code for availability check |
regionCode |
string | null | Region code for availability check |
Response (200):
{
"id": "...",
"lineItems": [ /* ... */ ],
"subTotal": 89.97,
"tax": 18.00,
"shipping": 5.99,
"discount": 0,
"total": 113.96,
"currencySymbol": "\u00a3",
"itemCount": 3,
"availability": [ /* only if includeAvailability=true */ ]
}
GET /basket/count¶
Lightweight endpoint that returns just the item count and formatted total. Use this to update a basket badge/icon without fetching the full basket.
Response (200):
POST /basket/update¶
Update the quantity of a line item in the basket.
Request body:
Response (200): Returns the updated basket (same shape as GET /basket).
DELETE /basket/{lineItemId}¶
Remove a specific line item from the basket.
Path parameters:
| Parameter | Type | Description |
|---|---|---|
lineItemId |
Guid | The line item to remove |
Response (200): Returns the updated basket.
POST /basket/clear¶
Remove all items from the basket. This deletes the entire basket.
Response (200):
GET /basket/availability¶
Check stock availability for all items currently in the basket.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
countryCode |
string | Country to check availability for |
regionCode |
string | Region to check availability for |
Response (200): Returns availability status per line item, including whether each item can ship to the specified location.
GET /basket/estimated-shipping¶
Get an estimated shipping cost for the basket. Automatically selects the cheapest shipping option per warehouse group.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
countryCode |
string | Destination country (uses storefront location if omitted) |
regionCode |
string | Destination region |
Response (200):
{
"success": true,
"estimatedShippingTotal": 5.99,
"formattedEstimatedShippingTotal": "\u00a35.99",
"basket": { /* ... */ }
}
If shipping cannot be estimated (empty basket, no location), the response includes success: false with an error message.
Tip: Display this on the basket page to give customers a shipping estimate before they enter checkout.
Shipping and Location Endpoints¶
GET /shipping/countries¶
Get the list of countries you ship to, plus the customer's current country selection and currency.
Response (200):
{
"countries": [
{ "code": "GB", "name": "United Kingdom" },
{ "code": "US", "name": "United States" }
],
"currentCountry": { "code": "GB", "name": "United Kingdom" },
"currency": { "currencyCode": "GBP", "currencySymbol": "\u00a3" }
}
Note: The country list is derived from your warehouse service regions. Only countries with active shipping configuration appear here.
GET /shipping/country¶
Get just the customer's current shipping country preference.
Response (200):
POST /shipping/country¶
Set the customer's shipping country. This also automatically updates the currency based on your country-to-currency mapping and converts any existing basket amounts.
Request body:
Response (200): Returns the selected country and new currency.
Response (400): Returned if the country code is invalid or currency conversion fails.
Warning: Changing the country triggers a basket currency conversion. If the basket has items, all amounts are recalculated at the current exchange rate.
GET /shipping/countries/{countryCode}/regions¶
Get available regions (states/provinces) for a specific country.
Path parameters:
| Parameter | Type | Description |
|---|---|---|
countryCode |
string | ISO country code (e.g., US, CA) |
Response (200):
{
"countryCode": "US",
"regions": [
{ "regionCode": "CA", "name": "California" },
{ "regionCode": "NY", "name": "New York" }
]
}
Currency Endpoints¶
GET /currency¶
Get the current storefront currency.
Response (200):
POST /currency¶
Override the storefront currency. If the basket has items, all amounts are converted to the new currency.
Request body:
Response (200): Returns the new currency details.
Response (400): Returned if the currency code is invalid or conversion fails.
Product Availability¶
GET /products/{productId}/availability¶
Check whether a specific product is available for purchase, optionally at a specific location.
Path parameters:
| Parameter | Type | Description |
|---|---|---|
productId |
Guid | The product variant ID |
Query parameters:
| Parameter | Type | Default | Description |
|---|---|---|---|
countryCode |
string | null | Check availability for this country |
regionCode |
string | null | Check availability for this region |
quantity |
int | 1 | Quantity to check |
Response (200): Returns availability information including stock status and shipping eligibility.
Response (404): Product not found.
Upsell Endpoints¶
Base URL: /api/merchello/storefront/upsells
GET /¶
Get upsell suggestions for the current basket at a specific display location.
Query parameters:
| Parameter | Type | Description |
|---|---|---|
location |
enum | Display location: ProductPage, Basket, Checkout, etc. |
countryCode |
string | For tax/availability calculations |
regionCode |
string | For tax/availability calculations |
Response (200):
[
{
"upsellRuleId": "...",
"heading": "You might also like",
"message": "Customers who bought this also bought...",
"checkoutMode": "AddToBasket",
"defaultChecked": false,
"products": [
{
"productId": "...",
"name": "Widget Pro",
"sku": "WIDGET-PRO",
"price": 29.99,
"formattedPrice": "\u00a329.99",
"imageUrl": "/media/widget-pro.jpg",
"availableForPurchase": true,
"hasVariants": false
}
]
}
]
Note: Impressions are automatically recorded when suggestions are returned. You don't need to track impressions manually unless you want finer-grained analytics.
GET /product/{productId}¶
Get upsell suggestions for a specific product page.
Path parameters:
| Parameter | Type | Description |
|---|---|---|
productId |
Guid | The product to get suggestions for |
Query parameters: Same as the basket upsells endpoint (countryCode, regionCode).
Response (200): Same format as the basket upsells endpoint.
POST /events¶
Record upsell analytics events (impressions, clicks) in batch.
Request body:
{
"events": [
{
"upsellRuleId": "...",
"displayLocation": "ProductPage",
"productId": "...",
"eventType": "Click"
}
]
}
Response (204): No content.
Saved Payment Methods¶
Base URL: /api/merchello/storefront/payment-methods
Note: All saved payment method endpoints require authentication. Customers can only access their own payment methods.
GET /¶
Get all saved payment methods for the current customer.
Response (200):
[
{
"id": "...",
"providerAlias": "stripe",
"methodType": "Card",
"cardBrand": "Visa",
"last4": "4242",
"expiryFormatted": "12/25",
"isExpired": false,
"displayLabel": "Visa ending in 4242",
"isDefault": true,
"iconHtml": "<svg>...</svg>"
}
]
Response (401): Customer not authenticated.
POST /setup¶
Create a vault setup session to add a new payment method. This initiates the process with the payment provider (e.g., creates a Stripe SetupIntent).
Request body:
{
"providerAlias": "stripe",
"methodAlias": "card",
"returnUrl": "https://example.com/account/payment-methods",
"cancelUrl": "https://example.com/account/payment-methods"
}
Response (200):
{
"success": true,
"setupSessionId": "...",
"clientSecret": "seti_..._secret_...",
"redirectUrl": null,
"sdkConfig": { /* provider-specific SDK configuration */ }
}
POST /confirm¶
Confirm a vault setup and save the payment method after the customer completes the provider-side flow.
Request body:
{
"providerAlias": "stripe",
"setupSessionId": "...",
"paymentMethodToken": "pm_...",
"providerCustomerId": "cus_...",
"setAsDefault": true
}
Response (200): Returns the newly saved payment method.
POST /{id}/set-default¶
Set a saved payment method as the default.
Response (200): { "success": true, "message": "Default payment method updated." }
Response (404): Payment method not found or belongs to another customer.
DELETE /{id}¶
Delete a saved payment method.
Response (200): { "success": true, "message": "Payment method deleted." }
Response (404): Payment method not found or belongs to another customer.
GET /providers¶
Get available vault-enabled payment providers. Only providers that support vaulted payments and have vaulting enabled are returned.
Response (200):