Store & Delivery

Everything you need to set up the store picker, display store details, and configure delivery options.

What you'll learn

  • How multi-store groups work and how to build a store picker
  • How to fetch store details, settings, and configuration
  • How delivery methods (pickup vs delivery) are determined
  • How to read store schedules and time-slot availabilities
  • How to list available payment options
  • How to display promotional banners, social links, and custom pages

Prerequisites

  • A Store UUID (staging: e87437f2-3e35-4738-af5e-6307e368255c)
  • A Group UUID for multi-store setups (sent via X-Group header)
  • cURL or any HTTP client

All endpoints in this guide use the jwt_optional_authenticated pipeline — no login token is required for read operations.


Store Picker (Multi-Store Groups)

Stores can belong to a group — a collection of locations that share branding and configuration. The store picker lets customers choose which location to browse.

How it works

  1. The frontend sends the group identifier via the X-Group header
  2. GET /api/v1/groups/stores returns all active stores in that group
  3. The customer selects a store, and subsequent requests use that store's UUID in the X-Store header

GET /api/v1/groups/stores

Headers: X-Group (required)

cURL

curl -X GET https://ecom-api.staging.blaze.me/api/v1/groups/stores \
  -H "Content-Type: application/vnd.api+json" \
  -H "Accept: application/vnd.api+json" \
  -H "X-Group: YOUR_GROUP_UUID"

JavaScript (fetch)

const GROUP_UUID = "YOUR_GROUP_UUID";
const BASE_URL = "https://ecom-api.staging.blaze.me";

const response = await fetch(`${BASE_URL}/api/v1/groups/stores`, {
  headers: {
    "Content-Type": "application/vnd.api+json",
    Accept: "application/vnd.api+json",
    "X-Group": GROUP_UUID,
  },
});

const { data } = await response.json();

// Build the store picker from the list
data.forEach((store) => {
  console.log(`${store.attributes.name}${store.attributes.address}`);
});

Response

{
  "data": [
    {
      "id": "e87437f2-3e35-4738-af5e-6307e368255c",
      "type": "stores",
      "attributes": {
        "name": "Downtown Dispensary",
        "address": {
          "address": "123 Main St",
          "city": "Los Angeles",
          "state": "CA",
          "zip_code": "90001",
          "country": "US",
          "lat": 34.0522,
          "lng": -118.2437
        },
        "uuid": "e87437f2-3e35-4738-af5e-6307e368255c",
        "timezone": "America/Los_Angeles",
        "is_active": true,
        "allow_pickup": true,
        "allow_deliveries": true,
        "thumbnail": "https://images.example.com/store-logo.png",
        "license_number": "C10-0000001-LIC",
        "is_demo": false,
        "merchant_id": "merchant-123"
      }
    },
    {
      "id": "b1234567-abcd-efgh-ijkl-000000000002",
      "type": "stores",
      "attributes": {
        "name": "Westside Location",
        "address": { "...": "..." },
        "is_active": true,
        "allow_pickup": true,
        "allow_deliveries": false
      }
    }
  ]
}

Tip: Use allow_pickup and allow_deliveries to show the correct delivery method options for each store in your picker UI.


Store Details

Once a store is selected, fetch its full details.

GET /api/v1/store

Headers: X-Store (required)

cURL

curl -X GET https://ecom-api.staging.blaze.me/api/v1/store \
  -H "Content-Type: application/vnd.api+json" \
  -H "Accept: application/vnd.api+json" \
  -H "X-Store: e87437f2-3e35-4738-af5e-6307e368255c"

JavaScript (fetch)

const STORE_UUID = "e87437f2-3e35-4738-af5e-6307e368255c";
const BASE_URL = "https://ecom-api.staging.blaze.me";

const response = await fetch(`${BASE_URL}/api/v1/store`, {
  headers: {
    "Content-Type": "application/vnd.api+json",
    Accept: "application/vnd.api+json",
    "X-Store": STORE_UUID,
  },
});

const { data } = await response.json();
console.log(data.attributes.name);
console.log(data.attributes.timezone);

Response

{
  "data": {
    "id": "e87437f2-3e35-4738-af5e-6307e368255c",
    "type": "stores",
    "attributes": {
      "name": "Downtown Dispensary",
      "uuid": "e87437f2-3e35-4738-af5e-6307e368255c",
      "env": "staging",
      "address": {
        "address": "123 Main St",
        "city": "Los Angeles",
        "state": "CA",
        "zip_code": "90001",
        "country": "US",
        "lat": 34.0522,
        "lng": -118.2437
      },
      "timezone": "America/Los_Angeles",
      "is_active": true,
      "allow_pickup": true,
      "allow_deliveries": true,
      "license_number": "C10-0000001-LIC",
      "is_demo": false,
      "merchant_id": "merchant-123",
      "thumbnail": "https://images.example.com/store-logo.png"
    },
    "relationships": {
      "site": { "data": { "id": "...", "type": "store_sites" } },
      "group": { "data": { "id": "...", "type": "groups" } }
    }
  }
}

Key attributes:

  • allow_pickup / allow_deliveries — determines which delivery methods are available
  • timezone — IANA timezone, important for interpreting schedules and availability slots
  • is_active — whether the store is currently active and accepting orders
  • address — full address object with coordinates for map rendering

Store Settings

GET /api/v1/store/settings

Returns the combined store and site settings for the current store. This includes feature flags, UI configuration, and operational settings used by the storefront.

curl -X GET https://ecom-api.staging.blaze.me/api/v1/store/settings \
  -H "Content-Type: application/vnd.api+json" \
  -H "Accept: application/vnd.api+json" \
  -H "X-Store: e87437f2-3e35-4738-af5e-6307e368255c"

GET /api/v2/store/settings

The v2 endpoint returns full settings — an aggregated response including the store group's stores, their individual settings, and group-level settings. This is typically used by the storefront to bootstrap the entire application state in a single call.

curl -X GET https://ecom-api.staging.blaze.me/api/v2/store/settings \
  -H "Content-Type: application/vnd.api+json" \
  -H "Accept: application/vnd.api+json" \
  -H "X-Store: e87437f2-3e35-4738-af5e-6307e368255c"

Store Configuration

GET /api/v1/store/configuration

Returns store configuration including the associated group and site information. This is primarily used by Mission Control (the admin dashboard).

curl -X GET https://ecom-api.staging.blaze.me/api/v1/store/configuration \
  -H "Content-Type: application/vnd.api+json" \
  -H "Accept: application/vnd.api+json" \
  -H "X-Store: e87437f2-3e35-4738-af5e-6307e368255c"

Delivery Methods: Pickup vs Delivery

The store's allow_pickup and allow_deliveries attributes determine which fulfillment methods are available. These flags affect:

  • Which schedules are relevant (pickup or delivery)
  • Which availability windows to show
  • Which payment options are returned (some are delivery-type specific)

When building the checkout flow, pass the delivery_type query parameter to endpoints that support it:

  • pickup — customer picks up at the store
  • scheduled_delivery — store delivers to the customer's address

Delivery Address Requirements

This section covers the full delivery address flow: what fields are required, how to validate an address, and what errors to expect.

Address Fields by Delivery Mode

Pickup — no customer address is needed. The store's own address is used automatically when the delivery specification type is pickup.

Delivery — a customer address is required. The exact fields depend on the store's delivery configuration:

  • Always required: zip_code
  • Required for full address validation: address, city, state, zip_code, country
  • lat / lng (geo data): required when the store uses region geo-zone restrictions (the use_region_geo_zones_restrictions setting). When enabled, the API uses geographic coordinates to determine whether the address falls within a delivery region polygon. Without this setting, only zip_code is checked against the store's delivery zones.
  • state: required when country is US or CA
  • country: defaults to US if omitted

Tip: Check the store settings endpoint (GET /api/v2/store/settings) for the use_region_geo_zones_restrictions flag to determine whether your integration needs to collect lat/lng from users.

Delivery Specification Structure

The delivery_specification object is set on the cart during creation or update. It tells the API how the order will be fulfilled.

{
  "delivery_specification": {
    "type": "delivery",
    "mode": "asap",
    "address": {
      "address": "123 Main St",
      "address_line2": "Apt 4B",
      "city": "Los Angeles",
      "state": "CA",
      "zip_code": "90001",
      "country": "US",
      "lat": 34.0522,
      "lng": -118.2437
    },
    "scheduled_start_time": null,
    "scheduled_end_time": null,
    "delivery_inventories": []
  }
}

Fields:

  • type (required) — pickup, delivery, or kiosk
  • mode (required) — asap, scheduled, or express
    • asap — deliver/pick up as soon as possible
    • scheduled — deliver/pick up at a chosen time slot (requires scheduled_start_time and scheduled_end_time)
    • express — express delivery (requires geo-zone support and available express inventory)
  • address — the delivery address object (required when type is delivery; ignored for pickup since the store address is used)
  • scheduled_start_time / scheduled_end_time — ISO 8601 datetime, required when mode is scheduled
  • delivery_inventories — optional array of inventory IDs to restrict which inventory fulfills the order (used with express delivery)

Address Validation Flow

Before setting the delivery specification on a cart, validate that the store delivers to the customer's address:

  1. User enters address → call POST /api/v3/deliveries/stores (or v4) with the address
  2. If deliverable → the response returns stores that can deliver. Set the delivery_specification on the cart via PUT /api/v4/carts/{cart_uuid}/delivery-specification or include it during cart creation/update
  3. If not deliverable → the response returns an error with code no_deliveries_at_location

v3 vs v4: Use v3 when you don't need express delivery or geo-zone support. Use v4 when the store has use_region_geo_zones_restrictions enabled or when you need express/scheduled mode filtering. The v4 response includes richer data like unavailable_reason, alternative_mode, and inventory details.

Verify Delivery Address

cURL
curl -X POST https://ecom-api.staging.blaze.me/api/v4/deliveries/stores \
  -H "Content-Type: application/vnd.api+json" \
  -H "Accept: application/vnd.api+json" \
  -H "X-Store: e87437f2-3e35-4738-af5e-6307e368255c" \
  -d '{
    "data": {
      "type": "addresses",
      "attributes": {
        "address": {
          "address": "123 Main St",
          "city": "Los Angeles",
          "state": "CA",
          "zip_code": "90001",
          "country": "US",
          "lat": 34.0522,
          "lng": -118.2437
        },
        "preferred_inventories": null,
        "mode": null
      }
    }
  }'
JavaScript (fetch)
const STORE_UUID = "e87437f2-3e35-4738-af5e-6307e368255c";
const BASE_URL = "https://ecom-api.staging.blaze.me";

async function verifyDeliveryAddress(address) {
  const response = await fetch(`${BASE_URL}/api/v4/deliveries/stores`, {
    method: "POST",
    headers: {
      "Content-Type": "application/vnd.api+json",
      Accept: "application/vnd.api+json",
      "X-Store": STORE_UUID,
    },
    body: JSON.stringify({
      data: {
        type: "addresses",
        attributes: {
          address: {
            address: address.street,
            city: address.city,
            state: address.state,
            zip_code: address.zipCode,
            country: address.country,
            lat: address.latitude,
            lng: address.longitude,
          },
          preferred_inventories: null,
          mode: null,
        },
      },
    }),
  });

  const result = await response.json();

  if (!response.ok) {
    // Handle no_deliveries_at_location or missing_zip_code errors
    throw new Error(
      result.errors?.[0]?.detail || "Address verification failed",
    );
  }

  return result.data; // Array of delivery_stores
}

Set Delivery Specification on Cart

cURL
curl -X PUT https://ecom-api.staging.blaze.me/api/v4/carts/CART_UUID/delivery-specification \
  -H "Content-Type: application/vnd.api+json" \
  -H "Accept: application/vnd.api+json" \
  -H "X-Store: e87437f2-3e35-4738-af5e-6307e368255c" \
  -d '{
    "data": {
      "id": "CART_UUID",
      "type": "carts",
      "attributes": {
        "delivery_specification": {
          "type": "delivery",
          "mode": "scheduled",
          "address": {
            "address": "123 Main St",
            "city": "Los Angeles",
            "state": "CA",
            "zip_code": "90001",
            "country": "US",
            "lat": 34.0522,
            "lng": -118.2437
          },
          "scheduled_start_time": "2026-06-01T10:00:00",
          "scheduled_end_time": "2026-06-01T13:00:00"
        }
      }
    }
  }'
JavaScript (fetch)
async function setDeliverySpecification(cartUuid, spec) {
  const response = await fetch(
    `${BASE_URL}/api/v4/carts/${cartUuid}/delivery-specification`,
    {
      method: "PUT",
      headers: {
        "Content-Type": "application/vnd.api+json",
        Accept: "application/vnd.api+json",
        "X-Store": STORE_UUID,
      },
      body: JSON.stringify({
        data: {
          id: cartUuid,
          type: "carts",
          attributes: {
            delivery_specification: {
              type: spec.type, // "pickup" or "delivery"
              mode: spec.mode, // "asap", "scheduled", or "express"
              address: spec.address, // full address object
              scheduled_start_time: spec.scheduledStartTime || null,
              scheduled_end_time: spec.scheduledEndTime || null,
              delivery_inventories: spec.deliveryInventories || [],
            },
          },
        },
      }),
    },
  );

  return response.json();
}

Region-Based Delivery

Stores can define delivery regions — geographic zones (polygons) that determine:

  • Whether the store delivers to a given address
  • Which inventory is used to fulfill the order (different regions can have different product availability and pricing)
  • Delivery fees that may vary by region

When use_region_geo_zones_restrictions is enabled, the API uses the lat/lng coordinates to check if the address falls within a delivery region polygon (PostGIS ST_Contains). Without this setting, the API checks zip_code against a list of zip codes associated with each delivery region.

Region-based delivery affects:

  • Product availability — products may only be available in certain regions
  • Express delivery — only available in regions with inventories marked available_for_express
  • Delivery fees — may differ per region

Error Scenarios

These errors can occur during address validation or when setting the delivery specification:

Error Code HTTP Status Message When It Occurs
missing_zip_code 400 Zip code is required. zip_code not provided in the delivery address
invalid_zip_code 400 Zip code is invalid for {country}. zip_code format doesn't match the country (US or CA)
missing_address 400 Address is required. Delivery type requires an address but none was provided
geo_data_required 400 Delivery address geo location data is required for this delivery mode. Store uses geo-zone restrictions but lat/lng were not provided
zip_code_required 400 Delivery address Zip Code is required for this delivery mode. Delivery mode requires a zip code but none was provided
no_deliveries_at_location 400 Sorry, we don't deliver to that location. Address is outside all delivery zones for the store group
no_delivery_fee 400 We don't do deliveries to that location. Address is in a zone but no delivery fee could be calculated (store blocks orders without a fee)

Schedules

Schedules define the store's operating hours for each delivery method, broken down by weekday.

GET /api/v1/store/schedules/{schedule_type}

Path parameters:

  • schedule_typepickup or delivery

cURL

curl -X GET https://ecom-api.staging.blaze.me/api/v1/store/schedules/pickup \
  -H "Content-Type: application/vnd.api+json" \
  -H "Accept: application/vnd.api+json" \
  -H "X-Store: e87437f2-3e35-4738-af5e-6307e368255c"

JavaScript (fetch)

const STORE_UUID = "e87437f2-3e35-4738-af5e-6307e368255c";
const BASE_URL = "https://ecom-api.staging.blaze.me";

async function getSchedules(type) {
  const response = await fetch(`${BASE_URL}/api/v1/store/schedules/${type}`, {
    headers: {
      "Content-Type": "application/vnd.api+json",
      Accept: "application/vnd.api+json",
      "X-Store": STORE_UUID,
    },
  });
  return response.json();
}

// Fetch both schedule types
const pickupSchedules = await getSchedules("pickup");
const deliverySchedules = await getSchedules("delivery");

Response

{
  "data": [
    {
      "id": "monday",
      "type": "schedules",
      "attributes": {
        "weekday": "monday",
        "start_time": "09:00:00",
        "end_time": "21:00:00",
        "schedule_type": "pickup",
        "is_active": true
      }
    },
    {
      "id": "tuesday",
      "type": "schedules",
      "attributes": {
        "weekday": "tuesday",
        "start_time": "09:00:00",
        "end_time": "21:00:00",
        "schedule_type": "pickup",
        "is_active": true
      }
    },
    {
      "id": "sunday",
      "type": "schedules",
      "attributes": {
        "weekday": "sunday",
        "start_time": null,
        "end_time": null,
        "schedule_type": "pickup",
        "is_active": false
      }
    }
  ]
}

Note: A schedule with is_active: false means the store is closed on that day for that delivery type.


Availability Windows

While schedules define the store's general hours, availabilities return the actual bookable time slots for upcoming days. Use these to let customers pick a delivery or pickup window.

GET /api/v1/store/availabilities/{schedule_type}

Path parameters:

  • schedule_typepickup or delivery

Query parameters (optional):

  • filter[since] — start date (ISO 8601, e.g. 2026-05-30). Defaults to today in the store's timezone
  • filter[until] — end date. Defaults to 7 days after since
  • filter[has_available_slots]true to only return days with open slots
  • page[size] — limit the number of results
  • zip_code — filter availability by delivery zip code
  • coords — filter by geographic coordinates (for express delivery)
curl -X GET "https://ecom-api.staging.blaze.me/api/v1/store/availabilities/delivery?filter[since]=2026-05-30&filter[until]=2026-06-05" \
  -H "Content-Type: application/vnd.api+json" \
  -H "Accept: application/vnd.api+json" \
  -H "X-Store: e87437f2-3e35-4738-af5e-6307e368255c"

Response

{
  "meta": {
    "settings": {
      "delivery_type": "delivery",
      "timezone_id": "America/Los_Angeles",
      "since": "2026-05-30",
      "until": "2026-06-05"
    }
  },
  "data": [
    {
      "id": "2026-05-30",
      "type": "availabilities",
      "attributes": {
        "date": "2026-05-30",
        "weekday": "saturday",
        "slots": [
          {
            "start_time": "09:00:00",
            "end_time": "12:00:00",
            "available": true
          },
          {
            "start_time": "12:00:00",
            "end_time": "15:00:00",
            "available": true
          },
          {
            "start_time": "15:00:00",
            "end_time": "18:00:00",
            "available": false
          }
        ]
      }
    }
  ]
}

The meta.settings object contains the scheduling configuration (slot duration, lead time, etc.) along with the store's timezone.


Payment Options

GET /api/v1/store/payment-options

Returns the payment methods available for the store. Results can vary based on delivery type and device.

Query parameters (optional):

  • delivery_typepickup or scheduled_delivery; defaults to pickup
  • zip_code — providing a zip code automatically sets delivery type to delivery
  • coords — providing coordinates (express delivery) sets delivery type to delivery
curl -X GET "https://ecom-api.staging.blaze.me/api/v1/store/payment-options?delivery_type=pickup" \
  -H "Content-Type: application/vnd.api+json" \
  -H "Accept: application/vnd.api+json" \
  -H "X-Store: e87437f2-3e35-4738-af5e-6307e368255c"

Response

{
  "data": [
    {
      "id": "1",
      "type": "store_payment_options",
      "attributes": {
        "payment_option": "cash",
        "name": "Cash",
        "is_active": true,
        "external_service": null,
        "allows_tips": false,
        "allows_promotions": false,
        "supports_tips": false,
        "supports_promotions": false,
        "delivery_types": ["pickup", "delivery"]
      }
    },
    {
      "id": "2",
      "type": "store_payment_options",
      "attributes": {
        "payment_option": "debit",
        "name": "Debit Card",
        "is_active": true,
        "external_service": "aeropay",
        "allows_tips": true,
        "allows_promotions": true,
        "supports_tips": true,
        "supports_promotions": true,
        "delivery_types": ["pickup", "delivery"]
      }
    }
  ]
}

Key attributes:

  • payment_option — the payment type identifier (e.g. cash, debit, credit)
  • external_service — the payment provider if applicable (e.g. aeropay, merrco)
  • delivery_types — which fulfillment methods this payment option supports
  • allows_tips / allows_promotions — whether tips or promotions are enabled for this option
  • promotional_banner — optional banner to show alongside the payment option

Promotional Banners

GET /api/v1/store/site/promotional-banners

Returns active banners for the storefront hero carousel or announcements.

curl -X GET https://ecom-api.staging.blaze.me/api/v1/store/site/promotional-banners \
  -H "Content-Type: application/vnd.api+json" \
  -H "Accept: application/vnd.api+json" \
  -H "X-Store: e87437f2-3e35-4738-af5e-6307e368255c"

Response

{
  "data": [
    {
      "id": "1",
      "type": "promotional_banners",
      "attributes": {
        "title": "Summer Sale",
        "description": "20% off all edibles this weekend",
        "destination_url": "/products?category=edibles",
        "desktop_image_url": "https://images.example.com/banner-desktop.jpg",
        "mobile_image_url": "https://images.example.com/banner-mobile.jpg",
        "position": 1,
        "is_active": true,
        "active_from": "2026-05-01T00:00:00Z",
        "active_until": "2026-06-30T23:59:59Z",
        "sales_channels": ["web", "mobile"]
      }
    }
  ]
}

Use desktop_image_url and mobile_image_url for responsive rendering. The position field determines the display order. Filter by sales_channels to show only relevant banners for the current platform.


Social Networks

GET /api/v1/store/socials

Returns the store's social media links.

curl -X GET https://ecom-api.staging.blaze.me/api/v1/store/socials \
  -H "Content-Type: application/vnd.api+json" \
  -H "Accept: application/vnd.api+json" \
  -H "X-Store: e87437f2-3e35-4738-af5e-6307e368255c"

Response

{
  "data": [
    {
      "id": "instagram",
      "type": "store_social_networks",
      "attributes": {
        "name": "instagram",
        "link": "https://instagram.com/mystore",
        "is_active": true
      }
    },
    {
      "id": "twitter",
      "type": "store_social_networks",
      "attributes": {
        "name": "twitter",
        "link": "https://twitter.com/mystore",
        "is_active": true
      }
    }
  ]
}

Only display social links where is_active is true.


Custom Pages

GET /api/v1/store/pages

Returns custom content pages (e.g. About Us, Terms of Service) that can appear in the footer, header, or sidebar.

curl -X GET https://ecom-api.staging.blaze.me/api/v1/store/pages \
  -H "Content-Type: application/vnd.api+json" \
  -H "Accept: application/vnd.api+json" \
  -H "X-Store: e87437f2-3e35-4738-af5e-6307e368255c"

Response

{
  "data": [
    {
      "id": "1",
      "type": "store_pages",
      "attributes": {
        "name": "About Us",
        "link": "/about-us",
        "page_type": "custom",
        "description": "<p>Welcome to our store...</p>",
        "show_in_footer": true,
        "show_in_header": false,
        "show_in_side_bar": false,
        "show_in_app": true,
        "is_active": true,
        "is_external": false,
        "override_page": null,
        "group_page": false
      }
    },
    {
      "id": "2",
      "type": "store_pages",
      "attributes": {
        "name": "Terms of Service",
        "link": "/terms-of-service",
        "page_type": "custom",
        "show_in_footer": true,
        "show_in_header": false,
        "show_in_side_bar": false,
        "show_in_app": false,
        "is_active": true,
        "is_external": false,
        "override_page": null,
        "group_page": true
      }
    }
  ]
}

Key attributes:

  • show_in_footer / show_in_header / show_in_side_bar — controls where the page link appears
  • is_external — if true, link is a full URL; otherwise it's an internal path
  • group_page — if true, this page is shared across all stores in the group
  • description — HTML content of the page

Endpoint Reference

Endpoint Description
GET /api/v1/groups/stores List stores in a group (store picker)
GET /api/v1/store Store details
GET /api/v1/store/settings Store + site settings
GET /api/v2/store/settings Full settings (stores + group settings)
GET /api/v1/store/configuration Store configuration with group/site
GET /api/v1/store/schedules/{schedule_type} Schedules by type (pickup/delivery)
GET /api/v1/store/availabilities/{schedule_type} Time-slot availabilities
GET /api/v1/store/payment-options Available payment methods
GET /api/v1/store/site/promotional-banners Promotional banners
GET /api/v1/store/socials Social network links
GET /api/v1/store/pages Custom pages

What's Next

  • Browse products: See the Quick Start guide for product listing and filtering
  • Authentication: See the Authentication guide for login and JWT tokens
  • Cart & Checkout: Use the time slots from /store/availabilities/{type} when building the delivery specification for the cart