Only this pageAll pages
Powered by GitBook
1 of 49

LiquidCommerce APIs

Loading...

Loading...

Loading...

Services

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

CLOUD SDK

Loading...

Loading...

EVENTS & ERRORS

Loading...

Loading...

Loading...

Loading...

EVENT BRIDGE (WEBHOOKS)

Loading...

Use Cases

Loading...

Types

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Loading...

Authentication API Integration

The Authentication API serves as the primary gateway for secure access to LiquidCommerce Services

Authentication API Overview

The LiquidCommerce Authentication API provides a secure method to obtain an access token for all other API calls to LiquidCommerce Services. This token ensures secure access to various LiquidCommerce services and enables seamless integration into applications.

Key Features

  • Obtain Access Tokens: Retrieve a token for API authentication.

  • Secure API Access Management: Safeguard API access through token-based authentication.

  • Service Integration: Integrate LiquidCommerce services into your applications efficiently.

Base URLs

These URLs serve as the base for all LiquidCommerce API calls, depending on the environment (staging or production).

  • Staging: https://staging.api.liquidcommerce.cloud

  • Production: https://api.liquidcommerce.cloud

Using the Access Token

After obtaining the , include it in the Authorization header of subsequent API calls to other LiquidCommerce services.

Token Lifecycle

  1. Initial Authentication: Exchange API key for access token

  2. Token Usage: Include token in Authorization header

  3. Token Refresh: Use refresh mechanism before expiration

  4. Token Invalidation: Automatic expiry

Access Token Refresh

All API endpoints that require authentication now support token refreshing. This is done by including a refresh parameter in the request body.

Request Body Parameter

Parameter
Type
Description

Response

When refresh is set to true, the API response will include an auth object containing the new access token information.

Error Handling

The API uses standard HTTP response codes to indicate the success or failure of requests. In case of an error, the response body will contain a JSON object with more details about the error.

Rate Limiting

The Authentication API is subject to rate limiting to ensure fair usage and maintain performance. If you exceed the rate limit, you'll receive a 429 (Too Many Requests) response.

Best Practices

  • Store the access token securely on the client-side.

  • Include the refresh parameter when making requests close to the token's expiration time.

  • Update the stored access token whenever a new one is received in the auth object of a response.

Implement proper error handling for cases where token refresh fails.

refresh

boolean

When set to true, a new access token will be generated and returned

access token
Authorization: Bearer <YOUR_ACCESS_TOKEN>
{
    "auth": {
        "token": "<NEW_ACCESS_TOKEN>",
        "type": "ACCESS_TOKEN",
        "exp": 1722920383204
    },
    // ... other response data
}

LiquidCommerce Documentation

LiquidCommerce offers an enterprise-grade API Services for the beverage alcohol industry with real-time processing and AI-powered e-commerce features

Our APIs offer a comprehensive set of tools for managing product catalogs, processing orders, handling payments, and much more. By leveraging advanced technologies such as AI and real-time data processing, LiquidCommerce APIs enable businesses to create sophisticated, efficient, and personalized shopping experiences.

You can access all the available API calls as a POSTMAN collection configured with pre/post request scripts. LiquidCommerce Cloud APIs POSTMAN Collection => * * If you don't have access to the LiquidCommerce Postman Partner Workspace reach out to your account rep for access * *

Key Features

  1. Highly Scalable Infrastructure: Our APIs are built on a robust, cloud-based infrastructure that dynamically allocates resources to meet growing demand, ensuring consistent performance even during peak times.

  2. Secure Data Management: We implement rigorous security measures to protect sensitive data and transactions, maintaining compliance with industry standards.

  3. Efficient API Interactions: Our comprehensive set of APIs allows for streamlined integration with various services such as address validation, catalog management, and order processing.

Services

LiquidCommerce offers a range of APIs to cover all aspects of e-commerce operations:

  1. Authentication: Securely manage access to LiquidCommerce services.

  2. Address: Validate and standardize shipping addresses.

  3. Users: Handle user account creation, management, and authentication.

  4. Catalog: Access our extensive product catalog with advanced search, filtering, and recommendation capabilities.

Base URLs

These URLs serve as the base for all LiquidCommerce API calls, depending on the environment.

  • Staging: https://staging.api.liquidcommerce.cloud

  • Production: https://api.liquidcommerce.cloud

Key Benefits

  • Enhanced Customer Experience: Leverage AI-powered recommendations and real-time inventory data to provide a seamless shopping experience.

  • Operational Efficiency: Automate and streamline various e-commerce processes, reducing manual work and potential errors.

  • Scalability: Easily handle increased traffic and transactions as your business grows.

  • Flexibility: Customize and integrate LiquidCommerce APIs to fit your specific business needs and existing systems.

Price Handling

All monetary amounts are stored as integers representing cents to avoid floating-point precision issues. This ensures accurate financial calculations and prevents rounding errors in currency operations. Examples:

  • $12.34 is stored as 1234 cents

  • $0.99 is stored as 99 cents

  • $100.00 is stored as 10000 cents

Display formatting to dollar amounts should only occur at the presentation layer.

Getting Started

To begin using LiquidCommerce APIs:

  1. Contact our sales team to set up an account and obtain API credentials.

  2. Review our comprehensive API documentation for each specific API.

  3. Use our SDKs or direct API calls to integrate LiquidCommerce services into your application.

  4. Test your integration in our sandbox environment before going live.

For detailed information on each API, including endpoints, request/response formats, and best practices, please refer to the individual API documentation pages.

Real-Time Data Processing: Support for real-time data processing and updates ensures accurate inventory levels and prevents overselling.
  • Unified Payment Processing: Integrated with Stripe, our payment system allows for quick retailer onboarding and supports various payment methods like Credit Cards, Apple Pay, Amazon Pay, Google Pay.

  • Cart: Manage shopping carts with features like adding/removing items, applying promotions, and calculating totals in real-time.

  • Checkout: Streamline the checkout process with customizable workflows.

  • Data-Driven Insights: Access comprehensive data and analytics to make informed business decisions.

  • Compliance: Stay compliant with industry regulations through our secure and standardized API processes.

  • Address API

    The LiquidCommerce Address API provides comprehensive address validation, standardization, and geocoding services optimized for beverage alcohol delivery and shipping

    Address API Overview

    It leverages Google Places API to offer address autocomplete functionality and retrieve geographical coordinates, enhancing the accuracy of shipping addresses and enabling location-based services.

    Key Features

    • Address autocomplete using Google Places API

    • Geocoding to obtain latitude and longitude for addresses

    • Validation of shipping addresses

    • Support for international addresses

    Authentication

    Before using the API, you need to obtain an access token from the . Include this token in the Authorization header of all API requests:

    Error Handling

    The API uses standard HTTP response codes to indicate the success or failure of requests. In case of an error, the response body will contain a JSON object with more details about the error.

    Rate Limiting

    The API is subject to rate limiting to ensure fair usage and maintain performance. If you exceed the rate limit, you'll receive a 429 (Too Many Requests) response.

    Best Practices

    1. Use the autocomplete endpoint to provide real-time suggestions as users type their address.

    2. Always use the place ID returned by the autocomplete endpoint to fetch detailed address information.

    3. Store both the formatted address and the geocoding data (latitude and longitude) for each validated address.

    4. Implement proper error handling to manage cases where address validation fails.

    Google Places API Key

    A Google Places API Key is required to use this service. You need to include this key in your requests to the Address API. For instructions on how to obtain a Google Places API Key, please refer to the

    Cart API

    The LiquidCommerce Cart API provides comprehensive cart management capabilities with real-time pricing, inventory verification, and multi-retailer support

    Overview

    This API provides functionality for adding items to a cart, updating quantities, applying promotional codes, and calculating totals based on product prices, shipping fees, and other applicable charges.

    Orders API

    The Orders API provides secure access to order data throughout the finalized states of the order lifecycle within the LiquidCommerce ecosystem.

    Overview

    This API allows retrieval of comprehensive order information through authenticated endpoints. Orders progress through a defined lifecycle with distinct statuses that reflect their current state in the system.

    Authentication

    The Orders API utilizes a secure encapsulated data environment that requires 2-legged authentication, which differs from the standard API key approach.

    2-Legged Authentication Flow

    • Request Access Token:

    Overview

    Our system implements two distinct approaches to handle exceptional situations:

    Cart Events

    Non-blocking notifications that allow operations to continue while reporting issues. The cart system is designed to be fault-tolerant, meaning it will try to complete operations even when encountering issues, returning events to describe what happened rather than failing completely.

    Order Statuses
    • created - Order has been successfully created in the system but processing has not yet begun

    • processing - Order is actively being processed (payment verification, inventory allocation, etc.)

    • canceled - Order has been canceled and will not be fulfilled

    • delivered - Order has been successfully delivered to the customer

    Error Handling

    The API uses standard HTTP response codes to indicate the success or failure of requests. In case of an error, the response body will contain a JSON object with more details about the error.

    Rate Limiting

    The API is subject to rate limiting to ensure fair usage and maintain performance. If you exceed the rate limit, you'll receive a 429 (Too Many Requests) response.

    Support

    If you have any questions or need assistance with the API, please contact our support team at [email protected]

    Checkout Status Codes

    Strict error handling that prevents invalid checkout operations. When an error occurs during checkout, the operation fails with a specific status code and message to help identify and resolve the issue.

    Learn more about Checkout Status Codes →

    Learn more about Cart Events →

    Support

    Our dedicated support team is available to assist you with API integration and usage. For any questions or issues, please contact [email protected].

    Support

    Our dedicated support team is available to assist you with API integration and usage. For any questions or issues, please contact [email protected].

    Authentication API
    Google Maps Platform documentation

    Support

    Our dedicated support team is available to assist you with API integration and usage. For any questions or issues, please contact [email protected].

    Send a request to the Authentication endpoint with your credentials
  • Format: userID:password (Base64 encoded)

  • Example: Authorization: Basic dXNlcklEOnBhc3N3b3Jk

  • Receive Access Token:

    • Upon successful authentication, the server returns an access token

    • The token has a limited validity period (default: 60 minutes)

  • Use Access Token:

    • Include the token in the Authorization header for all subsequent API requests

    • Format: Authorization: Bearer {access_token}

  • Example Authentication Request

    Example Authentication Response

    Token Expiration and Renewal

    Access tokens expire after their designated lifetime. When a token expires, you must request a new one using your credentials. Do not store access tokens for extended periods.

    Security Considerations

    • Never share your userID and password in client-side code

    • Store access tokens securely and transmit only over HTTPS

    • Implement token refresh logic to handle expiration during active sessions

    Authorization: Bearer <YOUR_ACCESS_TOKEN>
    POST order-authentication
    Host: staging.api.liquidcommerce.cloud
    Authorization: Basic dXNlcklEOnBhc3N3b3Jk
    Content-Type: application/json
    {
      "accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
      "tokenType": "Bearer",
      "expiresIn": 3600
    }
    Key Features
    • Create and update shopping carts

    • Add, remove, or modify items in the cart

    • Apply promotional codes

    • Calculate totals including product prices, shipping fees, and platform fees

    • Support for multiple retailers and fulfillment methods

    Authentication

    Before using the API, you need to obtain an access token from the Authentication API. Include this token in the Authorization header of all API requests:

    Error Handling

    The API uses standard HTTP response codes to indicate the success or failure of requests. In case of an error, the response body will contain a JSON object with more details about the error.

    Rate Limiting

    The Cart API is subject to rate limiting to ensure fair usage and maintain performance. If you exceed the rate limit, you'll receive a 429 (Too Many Requests) response.

    Best Practices

    1. Always include the loc object to ensure accurate pricing and availability.

    2. Use the id field to update an existing cart rather than creating a new one for each update.

    3. Handle the events array in the response to manage any warnings or informational messages.

    4. Regularly update the cart to reflect any changes in product availability or pricing.

    Support

    Our dedicated support team is available to assist you with API integration and usage. For any questions or issues, please contact .

    Get Access Token

    Use this endpoint with your API key to get an access token, which is essential for authenticating other API requests.

    Endpoint Details

    GET /authentication

    If you need assistance on obtaining your API key, contact

    Headers

    Header
    Value

    Response Details

    Field
    Type
    Description

    Metadata Object

    Auth Object

    Field
    Type
    Description

    Sample Request and Response

    Using the Access Token

    After obtaining the access token, include it in the Authorization header on any API calls to LiquidCommerce API Services.

    Access Token Refresh

    All API endpoints that require authentication now support token refreshing. This is done by including a refresh parameter in the request body.

    Request Body Parameter

    Parameter
    Type
    Description

    Response

    When refresh is set to true, the API response will include an auth object containing the new access token information.

    Error Handling

    The API uses standard HTTP response codes to indicate the success or failure of requests. In case of an error, the response body will contain a JSON object with more details about the error.

    Rate Limiting

    The Authentication API is subject to rate limiting to ensure fair usage and maintain performance. If you exceed the rate limit, you'll receive a 429 (Too Many Requests) response.

    Best Practices

    • Store the access token securely on the client-side.

    • Include the refresh parameter when making requests close to the token's expiration time.

    • Update the stored access token whenever a new one is received in the auth object of a response.

    Autocomplete

    Provides address suggestions based on user input

    Endpoint Details

    POST /address/autocomplete

    Headers

    Header
    Value

    Body

    Parameter
    Type
    Description
    Required

    Response Details

    Field
    Type
    Description

    Metadata Object

    Google Place Object

    Field
    Type
    Description

    Sample Request and Response

    Update Default Payment

    Update the default payment method for a user by ID

    Endpoint Details

    GET /users/payments/updateDefault/{userId}/{paymentId}

    Headers

    Header
    Value

    Path Parameters

    Name
    Type
    Description
    Required

    Response Details

    Field
    Type
    Description

    Metadata Object

    Field
    Type
    Description

    Sample Request and Response

    Fetch User

    Retrieve a user session information by ID

    Endpoint Details

    GET /users/fetch/{userId}

    Path Parameters

    Name
    Type
    Description
    Required

    Headers

    Header
    Value

    Response Details

    Field
    Type
    Description

    Metadata Object

    Sample Request and Response

    Catalog API

    The Catalog API provides access to LiquidCommerce's comprehensive beverage alcohol catalog, featuring intelligent search, dynamic filtering, and AI-powered recommendation capabilities

    Catalog API Overview

    The Catalog API allows you to:

    • Perform intelligent text searches with AI-powered natural language processing

    • Apply dynamic filters to refine product results in real-time

    • Sort results based on various criteria

    • Retrieve personalized product recommendations

    • Access content-enhanced searching for recipes and articles

    • Utilize advanced product tagging for diverse attributes

    Key Features

    • Enhanced Product Filtering and Sorting: Utilizes LiquidCommerce's real-time data processing for dynamic and accurate product filtering.

    • Intelligent Product Recommendations: Returns products using a proprietary recommendation engine powered by GCP Retail and Vertex AI, continuously training models for personalized suggestions.

    • Content Enhanced Searching, Filtering and Sorting: Returns the latest recipes and articles either through keywords or UPCs.

    Authentication

    Before using the API, you need to obtain an access token from the . Include this token in the Authorization header of all API requests:

    Error Handling

    The API uses standard HTTP response codes to indicate the success or failure of requests. In case of an error, the response body will contain a JSON object with more details about the error.

    Rate Limiting

    The API is subject to rate limiting to ensure fair usage and maintain performance. If you exceed the rate limit, you'll receive a 429 (Too Many Requests) response.

    Complete

    Completes a checkout process and creates the order

    Endpoint Details

    POST /checkout/complete

    Delete User

    Delete a user session information by ID

    Endpoint Details

    DELETE /users/purge/{userId}

    Checkout Events

    Checkout events indicate various checkout states and conditions. The system maintains fault tolerance by returning events instead of failing operations.

    Event Structure

    Event Enum

    Users API

    The LiquidCommerce User API provides functionality for managing user accounts within the LiquidCommerce ecosystem.

    Users API Overview

    This API handles all aspects of user data management, from account creation and authentication to profile management and secure data storage.

    Key Features

    Authorization: Bearer <YOUR_ACCESS_TOKEN>
    [email protected]

    data

    boolean

    Updating the payment to isDefault

    path

    string

    API path

    version

    string

    API version used for the request

    Content-Type

    application/json

    Authorization

    Bearer <YOUR_ACCESS_TOKEN>

    userId

    string

    Existing user identifier, returned upon session creation or update

    paymentId

    string

    Default payment identifier of the user

    statusCode

    number

    HTTP status code of the response

    message

    string

    A brief message describing the result of the API call

    metadata

    metaDataObject

    Contains metadata about the API call

    auth

    authObject

    Authentication object, only when refresh in true

    languages

    Array<string>

    List of supported languages for the response, e.g. ["en"]

    timestamp

    string

    Unix timestamp (in milliseconds) when the response was generated

    timezone

    string

    Timezone used for the response, always "UTC"

    requestId

    string

    Unique identifier for the API request. Used for debugging and support

    Advanced Product Tagging: Highlights diverse ownership, limited editions, and other key attributes, leveraging LiquidCommerce's flexible catalog management.
    Authentication API

    Support

    Our dedicated support team is available to assist you with API integration and usage. For any questions or issues, please contact [email protected].

    Event Types

    Checkout Modification Events

    • ItemQuantityChange: Item quantity reduced from ${originalQuantity} to ${stock} due to limited stock availability

    Validation Events

    • MaxQuantityPerOrderExceeded: The maximum quantity per order for this item is ${maxPresaleQuantity}. Quantity has been adjusted accordingly. || Quantity adjusted from ${originalQuantity} to ${quantity} due to presale availability

    • RetailerOnDemandHoursNotAvailable: The following cart item(s) have been removed due to retailer hours of operation restrictions

    Promo and Gift Cart Event Cases

    • ErrorProcessingGiftCards: There's been an error processing your gift card(s)

    • InvalidGiftCardCodes: The gift card code(s) you entered is invalid

    • InvalidGiftCardPartner: This gift card cannot be used with this merchant

    • InactiveGiftCard: This gift card is currently inactive

    • GiftCardAlreadyInUse: This gift card has already been used

    • GiftCardExpired: This gift card has expired

    • GiftCardBalanceDepleted: This gift card has no remaining balance

    • RetailerDoesNotAllowPromos: This retailer does not accept promo codes || None of the selected retailers accept promo codes || ${retailerNames} does not accept promo codes || Promo code applied. Note: ${retailerNames} does not accept promo codes || Promo code applied to eligible items only. The following retailers do not accept promo codes: ${retailerNames}

    • RetailersDoNotAllowPromos: Selected retailers do not accept promo codes || None of the selected retailers accept promo codes || ${retailerNames} does not accept promo codes || Promo code applied. Note: ${retailerNames} does not accept promo codes || Promo code applied to eligible items only. The following retailers do not accept promo codes: ${retailerNames}

    • RetailerDoesNotAllowGiftCards: Gift card applied. Note: ${retailerNames} does not accept gift cards || Gift card applied to eligible retailers only. The following retailers do not accept gift cards: ${retailerNames}

    • RetailersDoNotAllowGiftCards: ${retailerNames} does not accept gift cards || None of the selected retailers accept gift cards

    curl --location 'https://staging.api.liquidcommerce.cloud/users/payments/updateDefault' \
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
    --header 'Content-Type: application/json' \
    --data '{
        "customerId": "usrid_123abc456def",
        "paymentMethodId": "paymentid_123abc456def",
        "isDefault": false
    }'
    {
        "statusCode": 200,
        "message": "Updating default payment method succeeded",
        "metadata": {
            "languages": [
                "en"
            ],
            "timestamp": 1731600946784,
            "timezone": "UTC",
            "requestId": "reqid_123abc45def",
            "path": "/api/users/payments/updateDefault/usr_123abc456def/paymentid_123abc456def",
            "version": "1.7.0"
        },
        "data": true
    }
    Authorization: Bearer <YOUR_ACCESS_TOKEN>
    interface ICheckoutEvents {
      type: CHECKOUT_EVENT_ENUM;
      message: string;
      items?: Array<Partial<ICheckoutItem>>;
    }
    enum CHECKOUT_EVENT_ENUM {
      ERROR_PROCESSING_GIFT_CARDS = 'ErrorProcessingGiftCards',
      INVALID_GIFT_CARD_CODE = 'InvalidGiftCardCodes',
      INVALID_GIFT_CARD_PARTNER = 'InvalidGiftCardPartner',
      INACTIVE_GIFT_CARD = 'InactiveGiftCard',
      GIFT_CARD_ALREADY_IN_USE = 'GiftCardAlreadyInUse',
      GIFT_CARD_EXPIRED = 'GiftCardExpired',
      GIFT_CARD_BALANCE_DEPLETED = 'GiftCardBalanceDepleted',
      RETAILER_ONDEMAND_HOURS_NOT_AVAILABLE = 'RetailerOnDemandHoursNotAvailable',
      ITEM_QTY_CHANGE = 'ItemQuantityChange',
      MAX_QUANTITY_PER_ORDER_EXCEEDED = 'MaxQuantityPerOrderExceeded',
      RETAILER_DOES_NOT_ALLOW_PROMOS = 'RetailerDoesNotAllowPromos',
      RETAILERS_DO_NOT_ALLOW_PROMOS = 'RetailersDoNotAllowPromos',
      RETAILER_DOES_NOT_ALLOW_GIFT_CARDS = 'RetailerDoesNotAllowGiftCards',
      RETAILERS_DO_NOT_ALLOW_GIFT_CARDS = 'RetailersDoNotAllowGiftCards',
    }
    Implement proper error handling for cases where token refresh fails.

    Content-Type

    application/json

    X-LIQUID-API-KEY

    <YOUR_API_KEY>

    statusCode

    number

    Internal status code of the response

    message

    string

    A brief message describing the result of the API call

    metadata

    metaDataObject

    Contains metadata about the API call

    data

    authObject

    Authentication object

    token

    string

    The access token to be used for other API calls

    type

    string enum

    The type of token, always "ACCESS_TOKEN"

    exp

    number

    The expiration timestamp of the token (1 day)

    refresh

    boolean

    When set to true, a new access token will be generated and returned

    support

    Support

    Our dedicated support team is available to assist you with API integration and usage. For any questions or issues, please contact [email protected].

    data

    Array<>

    Array of Google Place ID objects

    Content-Type

    application/json

    Authorization

    Bearer <YOUR_ACCESS_TOKEN>

    input

    string

    Partial address input for autocomplete suggestions

    key

    string

    Your Google Places API key

    refresh

    boolean

    When set to true, a new access token will be generated and returned

    statusCode

    number

    HTTP status code of the response

    message

    string

    A brief message describing the result of the API call

    metadata

    metaDataObject

    Contains metadata about the API call

    auth

    authObject

    Authentication object, only when refresh in true

    id

    string

    Google Places API location identifier

    description

    string

    An address returned

    Headers
    Header
    Value

    Content-Type

    application/json

    Authorization

    Bearer <YOUR_ACCESS_TOKEN>

    Body

    Parameter
    Type
    Description
    Required

    token

    string

    Checkout token from prepare endpoint

    payment

    string

    Payment method ID or new payment token, you must use the to mount/inject a paymentElement to be able to generate a payment token.

    Response Details

    Field
    Type
    Description

    statusCode

    number

    Internal status code of the response

    message

    string

    A brief message describing the result of the API call

    metadata

    Contains metadata about the API call

    auth

    Authentication object, only when refresh in true

    Metadata Object

    Sample Request and Response

    Path Parameters
    Name
    Type
    Description
    Required

    userId

    string

    Existing user ID, returned upon session creation or update

    Headers

    Header
    Value

    Content-Type

    application/json

    Authorization

    Bearer <YOUR_ACCESS_TOKEN>

    Response Details

    Field
    Type
    Description

    statusCode

    number

    HTTP status code of the response

    message

    string

    A brief message describing the result of the API call

    metadata

    Contains metadata about the API call

    data.deleted

    boolean

    States if delete succeded or not

    Metadata Object

    Sample Request and Response

  • User creation

  • User management (update user information)

  • User Addresses

  • User Saved Payment Methods

  • Secure handling of Personally Identifiable Information (PII)

  • PCI DSS compliant data storage and transmission

  • Data Security and Compliance

    LiquidCommerce takes the security and privacy of user data very seriously. Our User API is designed with the following security measures:

    • PCI DSS Compliance: Our systems are fully compliant with the Payment Card Industry Data Security Standard (PCI DSS), ensuring that all sensitive payment information is handled securely.

    • Secure PII Handling: All Personally Identifiable Information (PII) is encrypted both in transit and at rest using industry-standard encryption protocols.

    • Data Minimization: We collect and store only the minimum amount of PII necessary for the operation of our services.

    • Access Control: Strict access controls and authentication mechanisms are in place to ensure that only authorized personnel can access user data.

    • Regular Audits: We conduct regular security audits and assessments to maintain the highest levels of data protection.

    • Data Retention: User data is retained only for as long as necessary and in compliance with applicable laws and regulations.

    • Data Purging: User data is permanently and securely erased using industry-standard deletion methods when no longer needed or upon request, ensuring complete removal from all systems including backups and archives.

    Authentication

    Before using the API, you need to obtain an access token from the Authentication API. Include this token in the Authorization header of all API requests:

    Error Handling

    The API uses standard HTTP response codes to indicate the success or failure of requests. In case of an error, the response body will contain a JSON object with more details about the error.

    Rate Limiting

    The API is subject to rate limiting to ensure fair usage and maintain performance. If you exceed the rate limit, you'll receive a 429 (Too Many Requests) response.

    Support

    Our dedicated support team is available to assist you with API integration and usage. For any questions or issues, please contact .

    userId

    string

    Existing user ID, returned upon session creation or update

    Content-Type

    application/json

    Authorization

    Bearer <YOUR_ACCESS_TOKEN>

    statusCode

    number

    HTTP status code of the response

    message

    string

    A brief message describing the result of the API call

    metadata

    metaDataObject

    Contains metadata about the API call

    data

    userType

    User object

    Delete Payment

    Delete a payment for a user by ID

    Endpoint Details

    DELETE /users/payments/purge/{userId}/{paymentId}

    Path Parameters

    Name
    Type
    Description
    Required

    Headers

    Header
    Value

    Response Details

    Field
    Type
    Description

    Metadata Object

    Sample Request and Response

    Checkout Status Codes

    Unlike cart events, checkout operations use strict error handling with specific status codes. When an error occurs, the operation fails with a corresponding error code and message.

    Status Enums

    Error Categories

    General Errors (548X)

    • 5480: Default checkout error

    • 5487: Parameter validation error

    • 5488: Tax calculation error

    Inventory & Location (548X)

    • 5481: Items out of stock at location

    • 5482: Location mismatch error

    Cart-Related (548X-549X)

    • 5484: Cart no longer available

    • 5485: Invalid cart ID

    • 5486: Issue with cart items

    Customer & Verification (548X-549X)

    • 5483: Age verification error

    • 5495: Customer account not found

    Checkout Process (548X-549X)

    • 5489: Invalid checkout token

    • 5490: Default completion error

    • 5491: Status update error

    Payment & Address (549X-550X)

    • 5496: Invalid payment method

    • 5497: Shipping address error

    • 5498: Invalid billing address

    Additional Services

    • 5503: Tips application error

    Add Payment

    Add a new payment method to a user by ID

    Endpoint Details

    POST /users/payments/add

    Headers

    Header
    Value

    Body

    Parameter
    Type
    Description
    Required

    Response Details

    Field
    Type
    Description

    Metadata Object

    Sample Request and Response

    Delete Address

    Delete an address for a user by address ID

    Endpoint Details

    DELETE /users/addresses/purge/{addressId}

    Path Parameters

    Name
    Type
    Description
    Required

    Headers

    Header
    Value

    Response Details

    Field
    Type
    Description

    Metadata Object

    Sample Request and Response

    Cart Events

    Cart events indicate various cart states and conditions. The system maintains fault tolerance by returning events instead of failing operations.

    Event Structure

    Event Enum

    Overview

    The LiquidCommerce Cloud SDK provides an easy way to interact with our APIs through a server-side SDK for Node.js and Web JS script.

    GitHub Repository: For the latest source code, issues, and contribution guidelines, visit our . Star the repo to stay updated with the latest changes.

    Table of Contents

    curl --location 'https://api.liquidcommerce.cloud/authentication'
    {
        "statusCode": 200,
        "message": "OK",
        "metadata": {
            "languages": [
                "en"
            ],
            "timestamp": 1731590739955,
            "timezone": "UTC",
            "requestId": "reqid_123abc45def",
            "path": "/api/authentication",
            "version": "1.7.0"
        },
        "data": {
            "token": "<YOUR_ACCESS_TOKEN>",
            "type": "ACCESS_TOKEN",
            "exp": 1731674132795
        }
    }
    {
        "statusCode": 5000,
        "message": "API Key not found",
        "metadata": {
            "languages": [
                "en"
            ],
            "timestamp": 1731592190265,
            "timezone": "UTC",
            "requestId": "reqid_123abc45def",
            "path": "/api/authentication",
            "version": "1.7.0"
        },
        "errors": []
    }
    Authorization: Bearer <YOUR_ACCESS_TOKEN>
    {
        "auth": {
            "token": "<NEW_ACCESS_TOKEN>",
            "type": "ACCESS_TOKEN",
            "exp": 1722920383204
        },
        // ... other response data
    }
    curl --location 'https://staging.api.liquidcommerce.cloud/address/autocomplete' \
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
    --header 'Content-Type: application/json' \
    --data '{
      "input": "100 Madison Ave, New",
      "key": "<YOUR_GOOGLE_PLACES_API_KEY>"
      "refresh": false"
    }'
    {
        "statusCode": 200,
        "message": "Get list address according to search.",
        "metadata": {
            "languages": [
                "en"
            ],
            "timestamp": 1731592446922,
            "timezone": "UTC",
            "requestId": "reqid_123abc45def",
            "path": "/api/address/autocomplete",
            "version": "1.7.0"
        },
        "data": [
            {
                "id": "placeid_123abc456ef",
                "description": "100 Madison Ave, Morristown, New Jersey, USA"
            },
            {
                "id": "placeid_789abc456ef",
                "description": "100 Madison Ave, New York, NY, USA"
            }
        ]
    }
    {
        "statusCode": 200,
        "message": "Processed your checkout and successfully charged the shopper.",
        "metadata": {
            "languages": [
                "en"
            ],
            "timestamp": 1731629320062,
            "timezone": "UTC",
            "requestId": "requestid_123abc456def",
            "path": "/api/checkout/complete",
            "version": "1.7.0"
        },
        "order": {
            "number": "ordernumber_1737134234213"
            "referenceId": "referenceid_123abc456def"
        }
    }
    curl --location 'https://staging.api.liquidcommerce.cloud/checkout/complete' \
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN'> \
    --header 'Content-Type: application/json' \
    --data-raw '{
        "token": "preparetoken_123abc456def",
        "payment": "paymentid_123abc456def"
    }'
    {
        "statusCode": 200,
        "message": "Deleting a customer",
        "metadata": {
            "languages": [
                "en"
            ],
            "timestamp": 1731597745591,
            "timezone": "UTC",
            "requestId": "reqid_123abc45def",
            "path": "/api/users/purge/usrid_123abc456def",
            "version": "1.7.0"
        },
        "data": {
            "deleted": true,
            "message": "Customer data purged successfully"
        }
    }
    curl --location --request DELETE 'https://staging.api.liquidcommerce.cloud/users/purge/usrid_123abc456def' \
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>'
    Authorization: Bearer <YOUR_ACCESS_TOKEN>
    curl --location 'https://staging.api.liquidcommerce.cloud/users/fetch/usrid_123abc456def'
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>'
    {
        "statusCode": 200,
        "message": "Get the selected user",
        "metadata": {
            "languages": [
                "en"
            ],
            "timestamp": 1731596453011,
            "timezone": "UTC",
            "requestId": "reqid_123abc45def",
            "path": "/api/users/fetch/usrid_123abc456def",
            "version": "1.7.0"
        },
        "data": {
            "id": "usr_123abc456def",
            "email": "[email protected]",
            "firstName": "John",
            "company": "",
            "lastName": "Smith",
            "phone": null,
            "profileImage": "",
            "birthDate": null,
            "createdAt": "2024-11-14T13:17:47.482Z",
            "updatedAt": "2024-11-14T14:50:54.613Z",
            "addresses": [],
            "savedPayments": []
        }
    }
    enum ENUM_CHECKOUT_STATUS_CODE_ERROR {
      REQUEST_DEFAULT_ERROR = 5480,
      REQUEST_LOCATION_OOS_ERROR = 5481,
      REQUEST_LOCATION_MISMATCH_ERROR = 5482,
      REQUEST_BIRTHDATE_ERROR = 5483,
      REQUEST_CART_NOT_AVAILABLE_ERROR = 5484,
      REQUEST_CART_ID_ERROR = 5485,
      REQUEST_CART_ITEM_ERROR = 5486,
      REQUEST_VALIDATION_ERROR = 5487,
      REQUEST_TAX_ERROR = 5488,
      REQUEST_COMPLETE_TOKEN = 5489,
      REQUEST_DEFAULT_COMPLETE_ERROR = 5490,
      REQUEST_CHECKOUT_COMPLETE_UPDATE_ERROR = 5491,
      REQUEST_CHECKOUT_COMPLETE_SAVE_ERROR = 5492,
      REQUEST_CHECKOUT_HAS_COMPLETE_ERROR = 5493,
      REQUEST_NO_CART_ITEM_ERROR = 5494,
      REQUEST_NO_CUSTOMER_FOUND_ERROR = 5495,
      REQUEST_PAYMENT_ATTACHED_ERROR = 5496,
      REQUEST_SHIPPING_ADDRESS_ERROR = 5497,
      REQUEST_BILLING_ADDRESS_ERROR = 5498,
      REQUEST_PAYMENT_NOT_FOUND_ERROR = 5499,
      REQUEST_CART_UPDATED_ERROR = 5501,
      REQUEST_ADDRESS_DEFAULT_ERROR = 5502,
      REQUEST_TIPS_ERROR = 5503,
      REQUEST_COMPLETE_CUSTOMER_MISSING_FIELDS = 5504,
      REQUEST_RETAILER_HOURS_ERROR = 5505,
      REQUEST_ITEM_QUANTITY_CHANGE_ERROR = 5506,
      REQUEST_MAX_QUANTITY_PER_ORDER_ERROR = 5507,
      REQUEST_PRESALE_NOT_STARTED_ERROR = 5508,
      REQUEST_CART_MIN_RETAILER_NOT_MET_ERROR = 5509,
      REQUEST_CHECKOUT_PROCESSING_LOCK_NOT_ACQUIRED_ERROR = 5510
    }
    
    enum ENUM_CHECKOUT_STATUS_CODE_MESSAGE {
      REQUEST_DEFAULT_ERROR = "There's been an error with your checkout request.",
      REQUEST_LOCATION_OOS_ERROR = 'The requested items are out of stock at this location.',
      REQUEST_LOCATION_MISMATCH_ERROR = "The selected location doesn't match your cart items.",
      REQUEST_BIRTHDATE_ERROR = 'Please verify your birthdate and try again.',
      REQUEST_CART_NOT_AVAILABLE_ERROR = 'This cart is no longer available.',
      REQUEST_CART_ID_ERROR = 'The cartId requested is invalid, check and try again.',
      REQUEST_CART_ITEM_ERROR = "There's an issue with one or more items in your cart.",
      REQUEST_VALIDATION_ERROR = "There's been an error with your request parameters, check and try again.",
      REQUEST_TAX_ERROR = 'There was an error calculating tax for your order.',
      REQUEST_COMPLETE_TOKEN = 'The checkout token provided is invalid, check and try again.',
      REQUEST_DEFAULT_COMPLETE_ERROR = 'There was an error completing your checkout, confirm through the (prepare) method and try again.',
      REQUEST_CHECKOUT_COMPLETE_UPDATE_ERROR = 'Unable to update your checkout status.',
      REQUEST_CHECKOUT_COMPLETE_SAVE_ERROR = 'Unable to save your completed checkout.',
      REQUEST_CHECKOUT_HAS_COMPLETE_ERROR = 'This checkout has already been processed, create a new cart to process a new checkout.',
      REQUEST_NO_CART_ITEM_ERROR = 'Item(s) in your cart are no longer available.',
      REQUEST_NO_CUSTOMER_FOUND_ERROR = 'The customer account was not found.',
      REQUEST_PAYMENT_ATTACHED_ERROR = 'The payment attached to the checkout is not a valid payment method for this customer.',
      REQUEST_SHIPPING_ADDRESS_ERROR = 'The address in your cart has changed, check and try again.',
      REQUEST_BILLING_ADDRESS_ERROR = 'The billing address in your checkout is not valid, check and try again.',
      REQUEST_PAYMENT_NOT_FOUND_ERROR = 'The payment method provided was not found.',
      REQUEST_CART_UPDATED_ERROR = 'The cart requested was updated during your checkout.',
      REQUEST_ADDRESS_DEFAULT_ERROR = "There's been an error with your address configurations in cart and/or billing address, check and try again.",
      REQUEST_TIPS_ERROR = "There's been an error applying your tips to the checkout.",
      REQUEST_COMPLETE_CUSTOMER_MISSING_FIELDS = 'Customer profile information is incomplete. Please provide all required details.',
      REQUEST_RETAILER_HOURS_ERROR = 'The retailer is currently closed or on-demand hours are not available.',
      REQUEST_ITEM_QUANTITY_CHANGE_ERROR = 'Some items in your cart exceed available stock quantities. Please adjust your cart and try again.',
      REQUEST_MAX_QUANTITY_PER_ORDER_ERROR = 'You have exceeded the maximum quantity allowed per order for one or more items in your cart.',
      REQUEST_PRESALE_NOT_STARTED_ERROR = 'The presale for this item has not started yet. Please check back later.',
      REQUEST_CART_MIN_RETAILER_NOT_MET_ERROR = 'Some items in your cart do not meet the minimum retailer requirements per order quantity. Please adjust your cart and try again.',
      REQUEST_CHECKOUT_PROCESSING_LOCK_NOT_ACQUIRED_ERROR = 'This checkout is currently being processed, please try again later.',
    }
    5494: Empty cart error
  • 5501: Cart updated during checkout

  • 5492: Unable to save checkout
  • 5493: Checkout already processed

  • 5510: Checkout currently being processed

  • 5499: Payment method not found
  • 5502: Address configuration error

  • [email protected]
    Event Types

    Inventory Events

    • OutOfStock: Requested items are not available in the desired quantity

    Cart Modification Events

    • ItemsNotAdded: Products could not be added to the cart

    • ItemsRequestedNotAdded: These item(s) requested can't be added to the cart either due to the location provided, and/or hours of operation.

    • RemovedExistingCartItems: The following cart item(s) have been removed, they're currently not available in the location provided

    • ItemQuantityChange: Item quantity reduced from ${originalQuantity} to ${stock} due to limited stock availability

    • ItemsRemoved: The following item(s) were removed from the cart due to zero quantity

    Validation Events

    • RetailerMinNotMet: The retailer minimum was not met, for item(s) (quantity:${quantity}, total price: ${price}) min(${min}).

    • NoItemsInCart: Cart is empty

    • InvalidId: The cartId provided is invalid, a new cart was created

    • NoId: The cartId provided is empty, a new cart was created

    • PresaleLimitExceeded: Presale fully reserved || Only ${n} units remaining for presale

    • PresaleNotStarted: Presale starts at ${date}

    • PresaleExpired: Presale reservation has expired || This presale has ended

    • PresaleMixedCart: Presale items cannot be mixed with regular items

    • RetailerFulfillmentInvalid: The retailer fulfillment ${fulfillmentId} selected, for item(s) with quantity:${quantity}, is invalid due to the fulfillment's allowed product type ${productTypesAllowed}.

    • MaxQuantityPerOrderExceeded: The maximum quantity per order for this item is ${maxPresaleQuantity}. Quantity has been adjusted accordingly. || Quantity adjusted from ${originalQuantity} to ${quantity} due to presale availability

    • RetailerOnDemandHoursNotAvailable: The following cart item(s) have been removed due to retailer hours of operation restrictions

    State Change Events

    • AddressChange: The provided location does not match the cart's location

    • CartCheckoutProcessed: The cartId (${id}) provided has already been processed through a checkout successfully

    • NewCart: No cart was found with the cartId (${id}), a new cart was created

    Special Cases

    • CartError: Default error event

    • ItemIdNotFound: The following item(s) with provided id were not found in the cart

    • ItemEngravingError: The item(s) selected for engraving is not engravable. || The item(s) selected for engraving is not currently active for engraving. || The item(s) selected for engraving has exceeded the maximum(${maxLines}) number of engraving lines. || The item(s) selected for engraving has exceeded the maximum(${engravingPersonalization.maxCharsPerLine}) characters limit per line.

    Coupon Event Cases

    • CouponProcessingError: There was an error processing this coupon

    • CouponNotFound: This coupon does not exist

    • CouponExpired: This coupon has expired

    • InvalidCoupon: This coupon is invalid

    • NoApplicableDiscount: This coupon results in no discount

    • CouponNotStarted: This coupon is not yet active

    • MinimumOrderValueNotMet: Order total does not meet minimum required value

    • MinimumOrderUnitsNotMet: Order does not meet minimum quantity requirement

    • MinimumDistinctItemsNotMet: Order does not meet minimum unique items requirement

    • QuotaExceeded: This coupon has reached its usage limit

    • UserLimitExceeded: Default error event

    • NotFirstPurchase: This coupon is only valid for first purchases

    • InvalidMembership: This coupon requires a specific membership

    • InvalidDomain: This coupon is restricted to specific email domains

    • InvalidRequirements: This coupon does not meet the required conditions

    • InvalidOrganization: This coupon is restricted to specific organizations

    • PresaleItemsNotAllowed: This coupon cannot be used with presale items

    • ProductNotEligible: One or more items are not eligible for this coupon

    • NotEnoughPreviousOrders: Previous order requirement not met

    • RetailerDoesNotAllowPromos: This retailer does not accept promo codes

    • RetailersDoNotAllowPromos: Selected retailers do not accept promo codes

    Checkout Only Event Cases

    • RetailerDoesNotAllowGiftCards: Gift card applied. Note: ${retailerNames} does not accept gift cards || Gift card applied to eligible retailers only. The following retailers do not accept gift cards: ${retailerNames}

    • RetailersDoNotAllowGiftCards: ${retailerNames} does not accept gift cards || None of the selected retailers accept gift cards

    interface ICartEvent {
      type: CART_EVENT_ENUM;
      message: string;
      items?: Array<Partial<ICartItem>>;
    }
    enum CART_EVENT_ENUM {
      OOS = 'OutOfStock',
      PRESALE_LIMIT_EXCEEDED = 'PresaleLimitExceeded',
      PRESALE_NOT_STARTED = 'PresaleNotStarted',
      PRESALE_EXPIRED = 'PresaleExpired',
      PRESALE_MIXED_CART = 'PresaleMixedCart',
      ITEMS_REQUESTED_NOT_ADDED = 'ItemsRequestedNotAdded',
      ITEM_NOT_ENGRAVED = 'ItemEngravingError',
      ADDRESS_CHANGE = 'AddressChange',
      REMOVED_EXISTING_ITEMS = 'RemovedExistingCartItems',
      RETAILER_MIN = 'RetailerMinNotMet',
      NO_ITEMS_IN_CART = 'NoItemsInCart',
      INVALID_ID = 'InvalidId',
      NO_ID = 'NoId',
      CART_CHECKOUT_PROCESSED = 'CartCheckoutProcessed',
      NEW_CART = 'NewCart',
      DEFAULT = 'CartError',
      ITEM_QTY_CHANGE = 'ItemQuantityChange',
      ITEM_ID_NOT_FOUND = 'ItemIdNotFound',
      ITEMS_REMOVED = 'ItemsRemoved',
      RETAILER_FULFILLMENT_INVALID = 'RetailerFulfillmentInvalid',
      MAX_QUANTITY_PER_ORDER_EXCEEDED = 'MaxQuantityPerOrderExceeded',
      RETAILER_ONDEMAND_HOURS_NOT_AVAILABLE = 'RetailerOnDemandHoursNotAvailable',
      COUPON_PROCESSING_ERROR = 'CouponProcessingError',
      COUPON_NOT_FOUND = 'CouponNotFound',
      COUPON_EXPIRED = 'CouponExpired',
      NO_APPLICABLE_DISCOUNT = 'NoApplicableDiscount',
      COUPON_NOT_STARTED = 'CouponNotStarted',
      MINIMUM_ORDER_VALUE_NOT_MET = 'MinimumOrderValueNotMet',
      MINIMUM_ORDER_UNITS_NOT_MET = 'MinimumOrderUnitsNotMet',
      MINIMUM_DISTINCT_ITEMS_NOT_MET = 'MinimumDistinctItemsNotMet',
      QUOTA_EXCEEDED = 'QuotaExceeded',
      NOT_FIRST_PURCHASE = 'NotFirstPurchase',
      INVALID_COUPON = 'InvalidCoupon',
      INVALID_MEMBERSHIP = 'InvalidMembership',
      INVALID_DOMAIN = 'InvalidDomain',
      INVALID_REQUIREMENTS = 'InvalidRequirements',
      INVALID_ORGANIZATION = 'InvalidOrganization',
      PRESALE_ITEMS_NOT_ALLOWED = 'PresaleItemsNotAllowed',
      PRODUCT_NOT_ELIGIBLE = 'ProductNotEligible',
      NOT_ENOUGH_PREVIOUS_ORDERS = 'NotEnoughPreviousOrders',
      RETAILER_DOES_NOT_ALLOW_PROMOS = 'RetailerDoesNotAllowPromos',
      RETAILERS_DO_NOT_ALLOW_PROMOS = 'RetailersDoNotAllowPromos',
      RETAILER_DOES_NOT_ALLOW_GIFT_CARDS = 'RetailerDoesNotAllowGiftCards',
      RETAILERS_DO_NOT_ALLOW_GIFT_CARDS = 'RetailersDoNotAllowGiftCards',
    }

    data.message

    string

    Delete message

    userId

    string

    Existing user identifier, returned upon session creation or update

    paymentId

    string

    Existing payment identifier of the user

    Content-Type

    application/json

    Authorization

    Bearer <YOUR_ACCESS_TOKEN>

    statusCode

    number

    HTTP status code of the response

    message

    string

    A brief message describing the result of the API call

    metadata

    metaDataObject

    Contains metadata about the API call

    data.deleted

    boolean

    States if delete succeded or not

    data

    User payment details

    Content-Type

    application/json

    Authorization

    Bearer <YOUR_ACCESS_TOKEN>

    userId

    string

    Identifier of the user to add payment method for

    paymentMethodId

    string

    Payment method ID or new payment token, you must use the CLOUD SDK to mount/inject a paymentElement to be able to generate a payment token.

    isDefault

    boolean

    Set as default payment method (default: false)

    statusCode

    number

    HTTP status code of the response

    message

    string

    A brief message describing the result of the API call

    metadata

    metaDataObject

    Contains metadata about the API call

    auth

    authObject

    Authentication object, only when refresh in true

    data.message

    string

    Delete message

    addressId

    string

    Existing user address identifier, returned upon address creation or update

    Content-Type

    application/json

    Authorization

    Bearer <YOUR_ACCESS_TOKEN>

    statusCode

    number

    HTTP status code of the response

    message

    string

    A brief message describing the result of the API call

    metadata

    metaDataObject

    Contains metadata about the API call

    data.deleted

    boolean

    States if delete succeded or not

    Authentication

  • Cloud SDK Demo

  • Usage

  • Response Types

  • Methods

    • Address

    • Catalog

    • Cart

  • Price Type

  • Documentation

  • Installation

    Authentication

    The LiquidCommerce Cloud SDK uses API keys to authenticate requests. You can request your keys from your Partnerships liaison.

    Your API keys carry many privileges, so be sure to keep them secure! Do not share your secret API keys in publicly accessible areas such as GitHub, client-side code, and so forth.

    All API requests in production must be made over HTTPS. Calls made over plain HTTP will fail. API requests without authentication will also fail.

    Cloud SDK Demo

    We've included a comprehensive demo application to help you quickly understand how to implement the LiquidCommerce Cloud SDK in real-world scenarios.

    Running the Demo

    1. Clone the repository:

    1. Navigate to the demo directory

    1. Add your API keys to the demo:

      • Open the demo directory in a code editor

      • Locate and edit the index.html file

      • Replace the placeholder values with your actual API keys:

      • Save the file

      ⚠️ Note: Keep your API keys secure and never commit them to public repositories.

    2. Start the development server by either:

    • Running pnpm run dev and opening http://localhost:3000/

    • Opening the file directly in your browser

    This browser-based demo demonstrates client-side implementation of the LiquidCommerce Cloud SDK including:

    • SDK initialization in the browser

    • API authentication flow

    • Address validation

    • Catalog browsing and product search

    • Shopping cart integration

    • User account management and session handling

    • Payment integration

    • Interactive checkout process

    • Orders

      • Authentication

      • Webhook Testing

      • Fetch By ID

    The demo uses vanilla JavaScript to ensure compatibility and clear understanding of SDK implementation without framework-specific code. 👉 View Demo Source Code

    GitHub repository
    Installation

    order.number

    string

    Order number

    order.referenceId

    string

    Order reference id

    CLOUD SDK
    metaDataObject
    authObject

    data.message

    string

    Delete message

    metaDataObject
    googlePlaceObject

    Create/Update Address

    Create or update an address for a user by ID

    Endpoint Details

    POST /users/addresses/add

    Headers

    Header
    Value

    Body

    Parameter
    Type
    Description
    Required

    Response Details

    Field
    Type
    Description

    Metadata Object

    Sample Request and Response

    Loc

    Below find the loc object reference for Liquid Commerce's location based configurations.

    The loc parameter provides 2 different options for location based information through the following parameters, at least 1 is required: *longitude and latitude are prioritized if included in the request*

    LocType

    Attribute
    Description

    Address

    Attribute
    Description

    Coords

    Attribute
    Description

    Additional Context

    Address: location information split out to individual values for the street, city, state, zip code and country. If you choose to use this option for your location, only the state is required.

    *ALL FIELDS REQUIRED FOR ON DEMAND AVAILABILITY*

    Longitude & Latitude: location information provided through an exact geospatial point by providing valid longitude and latitude coordinates values.

    Sample loc

    Loc Object

    Checkout API

    The LiquidCommerce Checkout API provides a secure, PCI-compliant transaction processing system optimized for beverage alcohol e-commerce

    Checkout API Overview

    This API handles the final steps of the purchasing process, including payment processing, order creation, and confirmation.

    Key Features

    • Secure payment processing

    • Order creation and management

    • Support for multiple payment methods

    • Integration with cart and inventory systems

    Security and Compliance

    The Checkout API is designed with security as a top priority:

    • PCI DSS Compliance: Fully compliant with Payment Card Industry Data Security Standard, ensuring secure handling of payment information.

    • Tokenization: Sensitive payment data is tokenized to minimize risk.

    • Encryption: All data is encrypted in transit and at rest.

    • Fraud Detection: Implements advanced fraud detection mechanisms.

    Authentication

    Before using the API, you need to obtain an access token from the . Include this token in the Authorization header of all API requests:

    Error Handling

    The API uses standard HTTP response codes to indicate the success or failure of requests. In case of an error, the response body will contain a JSON object with more details about the error.

    Checkout complete uses strict error handling with specific status codes.

    Rate Limiting

    The API is subject to rate limiting to ensure fair usage and maintain performance. If you exceed the rate limit, you'll receive a 429 (Too Many Requests) response.

    curl --location 'https://staging.api.liquidcommerce.cloud/users/payments/purge' \
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
    --header 'Content-Type: application/json' \
    --data '{
        "customerId": "usrid_123abc456def",
        "paymentMethodId": "paymentid_123abc456def",
        "isDefault": true
    }'
    {
        "statusCode": 200,
        "message": "Deleting a payment method",
        "metadata": {
            "languages": [
                "en"
            ],
            "timestamp": 1731600946784,
            "timezone": "UTC",
            "requestId": "reqid_123abc45def",
            "path": "/api/users/payments/purge/usr_123abc456def/paymentid_123abc456def",
            "version": "1.7.0"
        },
        "data": {
            "deleted": false,
            "message": "There's no Payment method with the ID provided for this customer"
        }
    }
    curl --location 'https://staging.api.liquidcommerce.cloud/users/payments/add' \
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
    --header 'Content-Type: application/json' \
    --data '{
        "customerId": "usrid_123abc456def",
        "paymentMethodId": "paymentid_123abc456def",
        "isDefault": true
    }'
    {
        "statusCode": 201,
        "message": "Adding an new payment method succeeded",
        "metadata": {
            "languages": [
                "en"
            ],
            "timestamp": 1731625068720,
            "timezone": "UTC",
            "requestId": "requestid_123abc456def",
            "path": "/api/users/payments/add",
            "version": "1.7.0"
        },
        "data": {
            "id": "paymentid_123abc456def",
            "type": "card",
            "isDefault": true,
            "card": {
                "brand": "visa",
                "country": "US",
                "expMonth": 11,
                "expYear": 2031,
                "last4": "1111",
                "funding": "credit"
            },
            "createdAt": "2024-11-14T22:57:49.094Z"
        }
    }
    curl --location --request DELETE 'https://staging.api.liquidcommerce.cloud/addresses/purge/addrid_123abc45def' \
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>'
    {
        "statusCode": 200,
        "message": "Deleting an address",
        "metadata": {
            "languages": [
                "en"
            ],
            "timestamp": 1731599013239,
            "timezone": "UTC",
            "requestId": "reqid_123abc45def",
            "path": "/api/users/addresses/purge/addrid_123abc45def",
            "version": "1.7.0"
        },
        "data": {
            "deleted": true,
            "message": "Address data purged successfully"
        }
    }
    const API_KEY = 'YOUR_LIQUIDCOMMERCE_API_KEY';
    const GOOGLE_PLACES_API_KEY = 'PUT_YOUR_KEY_HERE';
    
    // For Orders
    const ORDER_API_USER = 'YOUR_ORDER_API_USER';
    const ORDER_API_PASSWORD = 'YOUR_ORDER_API_PASSWORD';
    npm install @liquidcommerce/cloud-sdk
    # or
    yarn add @liquidcommerce/cloud-sdk
    git clone https://github.com/liquidcommerce/cloud-sdk.git
    cd cloud-sdk/demo
    User
    Payment Element
    Legacy Payment Element
    Checkout
    Orders

    zip code

    country: string [optional]

    country in which the address is located

    address: Address

    location information split out to individual values for the street, city, state, zip code and country. When using this option, all fields except country are required.

    coords: Coords

    location information provided through an exact geospatial point by providing valid longitude and latitude coordinates values. The numbers are in decimal degrees format and range from -90 to 90 for latitude and -180 to 180 for longitude

    id: string [optional]

    identifier of the address

    one: string [required]

    street address

    two: string [required]

    apt, suite, floor, etc

    city: string [required]

    city

    state: string [required]

    state, you can use either 2 letter code or the full name

    lat: number [required]

    latitude, ex: 40.744860

    long: number [required]

    longitude, ex: -73.985314

    zip: string [required]

    PCI DSS compliant
  • Real-time inventory checks

  • Support for promotional codes and discounts

  • Authentication API
    Checkout Status Codes

    Support

    Our dedicated support team is available to assist you with API integration and usage. For any questions or issues, please contact [email protected].

    "address": {
      // street address
      // REQUIRED
      "one": "string"; 
      // apt, suite, floor, etc
      // REQUIRED
      "two": "string";
      // city 
      // REQUIRED
      "city": "string";
      // state, you can use either 2 letter code or the full name
      // REQUIRED
      "state": "string";
      // zip code
      // REQUIRED
      "zip": "string";
      // country
      // OPTIONAL
      "country": "string";
    }
    // The numbers are in decimal degrees format and range 
    // from -90 to 90 for latitude and -180 to 180 for longitude
    "coords": {
       // latitude
       // REQUIRED
       "lat": "number", // ex: 40.744860
       // longitude
       // REQUIRED
       "long": "number" // ex: -73.985314
    }
    {
      "address":{
        "one": "100 Madison ave",
        "two": "apt 1707",
        "city": "New York",
        "state": "NY",
        "zip": "10016",
        "country": "US"
      },
      "coords": {
            "lat": 40.744860,
            "long": -73.985314
      }
    }
    Authorization: Bearer <YOUR_ACCESS_TOKEN>

    city

    string

    City name

    state

    string

    Two-letter state code or full state name

    zip

    string

    Postal/ZIP code

    type

    string

    Address type ('shipping' or 'billing')

    placesId

    string

    Google Places API location identifier

    lat

    number

    Latitude coordinate of address

    long

    number

    Longitude coordinate of address

    isDefault

    boolean

    Set as default address for type, default: false

    data

    Address object added

    Content-Type

    application/json

    Authorization

    Bearer <YOUR_ACCESS_TOKEN>

    userId

    string

    Identifier of the user to add address for

    one

    string

    Primary street address

    two

    string

    Secondary address (apt, suite, etc.)

    statusCode

    number

    HTTP status code of the response

    message

    string

    A brief message describing the result of the API call

    metadata

    metaDataObject

    Contains metadata about the API call

    auth

    authObject

    Authentication object, only when refresh in true

    Field
    Type
    Description
    userPayment
    Field
    Type
    Description

    User

    A full reference to user type for different Liquid Commerce APIs.

    UserType

    Attribute
    Description
    Field
    Type
    Description
    Field
    Type
    Description
    Field
    Type
    Description
    Field
    Type
    Description
    Field
    Type
    Description
    Field
    Type
    Description
    Field
    Type
    Description
    curl --location 'https://staging.api.liquidcommerce.cloud/users/addresses/add' \
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
    --header 'Content-Type: application/json' \
    --data '{
        "userId": "usrid_123abc456def",
        "one": "100 Madison Ave",
        "two": "Apt 1707",
        "city": "New York",
        "state": "NY",
        "zip": "10016",
        "type": "shipping",
        "placesId": "placeid_123abc456ef",
        "lat": 40.7447986,
        "long": -73.98530819999999,
        "isDefault": true
    }'
    {
        "statusCode": 201,
        "message": "Updating or creating an new address succeeded",
        "metadata": {
            "languages": [
                "en"
            ],
            "timestamp": 1731598717444,
            "timezone": "UTC",
            "requestId": "reqid_123abc45def",
            "path": "/api/users/addresses/add",
            "version": "1.7.0"
        },
        "data": {
            "id": "addrid_123abc45def",
            "type": "shipping",
            "one": "100 Madison Ave",
            "two": "Apt 1707",
            "city": "New York",
            "state": "NY",
            "zip": "10016",
            "lat": 40.7447986,
            "long": -73.98530819999999,
            "placesId": "placeid_123abc456ef",
            "country": "US",
            "createdAt": "2024-11-14T15:38:37.775Z",
            "updatedAt": "2024-11-14T15:38:37.775Z",
            "isDefault": true
        }
    }

    path

    string

    API path

    version

    string

    API version used for the request

    languages

    Array<string>

    List of supported languages for the response, e.g. ["en"]

    timestamp

    string

    Unix timestamp (in milliseconds) when the response was generated

    timezone

    string

    Timezone used for the response, always "UTC"

    requestId

    string

    Unique identifier for the API request. Used for debugging and support

    path

    string

    API path

    version

    string

    API version used for the request

    languages

    Array<string>

    List of supported languages for the response, e.g. ["en"]

    timestamp

    string

    Unix timestamp (in milliseconds) when the response was generated

    timezone

    string

    Timezone used for the response, always "UTC"

    requestId

    string

    Unique identifier for the API request. Used for debugging and support

    path

    string

    API path

    version

    string

    API version used for the request

    languages

    Array<string>

    List of supported languages for the response, e.g. ["en"]

    timestamp

    string

    Unix timestamp (in milliseconds) when the response was generated

    timezone

    string

    Timezone used for the response, always "UTC"

    requestId

    string

    Unique identifier for the API request. Used for debugging and support

    path

    string

    API path

    version

    string

    API version used for the request

    languages

    Array<string>

    List of supported languages for the response, e.g. ["en"]

    timestamp

    string

    Unix timestamp (in milliseconds) when the response was generated

    timezone

    string

    Timezone used for the response, always "UTC"

    requestId

    string

    Unique identifier for the API request. Used for debugging and support

    path

    string

    API path

    version

    string

    API version used for the request

    languages

    Array<string>

    List of supported languages for the response, e.g. ["en"]

    timestamp

    string

    Unix timestamp (in milliseconds) when the response was generated

    timezone

    string

    Timezone used for the response, always "UTC"

    requestId

    string

    Unique identifier for the API request. Used for debugging and support

    path

    string

    API path

    version

    string

    API version used for the request

    languages

    Array<string>

    List of supported languages for the response, e.g. ["en"]

    timestamp

    string

    Unix timestamp (in milliseconds) when the response was generated

    timezone

    string

    Timezone used for the response, always "UTC"

    requestId

    string

    Unique identifier for the API request. Used for debugging and support

    path

    string

    API path

    version

    string

    API version used for the request

    languages

    Array<string>

    List of supported languages for the response, e.g. ["en"]

    timestamp

    string

    Unix timestamp (in milliseconds) when the response was generated

    timezone

    string

    Timezone used for the response, always "UTC"

    requestId

    string

    Unique identifier for the API request. Used for debugging and support

    path

    string

    API path

    version

    string

    API version used for the request

    languages

    Array<string>

    List of supported languages for the response, e.g. ["en"]

    timestamp

    string

    Unix timestamp (in milliseconds) when the response was generated

    timezone

    string

    Timezone used for the response, always "UTC"

    requestId

    string

    Unique identifier for the API request. Used for debugging and support

    path

    string

    API path

    version

    string

    API version used for the request

    languages

    Array<string>

    List of supported languages for the response, e.g. ["en"]

    timestamp

    string

    Unix timestamp (in milliseconds) when the response was generated

    timezone

    string

    Timezone used for the response, always "UTC"

    requestId

    string

    userAddress

    Unique identifier for the API request. Used for debugging and support

    firstName: string

    user's first name

    lastName: string

    user's last name

    phone: string

    user's phone number

    company: string

    user's company

    profileImage: string

    url to user's profile image

    birthDate: string

    users's birth date

    createdAt: Date

    account creation timestamp

    updatedAt: Date

    last update timestamp

    addresses: Array<>

    user's saved addresses

    savedPayments: Array<>

    user's saved payment methods

    UserAddress

    Attribute
    Description

    id: string

    user address identifier

    placesId: string

    google places identifier

    one: string

    the primary street address or neighborhood

    two: string

    the secondary address information, such as apt or suit number

    city: string

    the name of the city

    UserPayment

    Attribute
    Description

    id: string

    user payment identifier

    type: string

    payment method type (e.g., credit card, paypal)

    isDefault: boolean

    whether this is the default payment method

    card: [optional]

    card details if payment method is a card

    createdAt: Date

    payment method creation timestamp

    SavedCard

    Attribute
    Description

    brand: string

    card brand (Visa, Mastercard, etc.)

    country: string

    card issuing country

    expMonth: number

    expiration month

    expYear: number

    expiration year

    last4: string

    last 4 digits of card number

    Sample user

    User Object

    id: string

    user's identifier

    email: string

    user's email address

    {
            "id": "userId_123abc12_123abc12",
            "email": "[email protected]",
            "firstName": "John",
            "company": "Liquid Commerce",
            "lastName": "Doe",
            "phone": "+1234567890",
            "profileImage": "https://example.com/profiles/sarah.jpg",
            "birthDate": "1990-05-15",
            "createdAt": "2024-09-15T10:30:25.123Z",
            "updatedAt": "2024-11-12T16:45:32.891Z",
            "addresses": [
                {
                    "id": "8d4e5f6g-7h8i-9j0k-lm12-34567890nopq",
                    "type": "shipping",
                    "one": "100 Madison Ave",
                    "two": "Floor 23",
                    "city": "New York",
                    "state": "NY",
                    "zip": "10166",
                    "country": "US",
                    "placesId": "ChIJKxDbe7lZwokRVf__________",
                    "lat": 40.754542,
                    "long": -73.976929,
                    "isDefault": true,
                    "createdAt": "2024-10-01T09:22:15.432Z",
                    "updatedAt": "2024-11-10T11:15:44.789Z"
                }
            ],
            "savedPayments": [
                {
                    "id": "pm_paymentId_123abc12",
                    "type": "card",
                    "isDefault": true,
                    "card": {
                        "brand": "visa",
                        "country": "US",
                        "expMonth": 12,
                        "expYear": 20**,
                        "last4": "****",
                        "funding": "credit"
                    },
                    "createdAt": "2024-10-15T14:30:20.555Z"
                }
            ],
            "session": {
                "key": "pk_test_51AbCdEfGhIjKl_________",
                "secret": "seti_1AbCdEfGhIjKlM_________",
                "createdAt": "2024-11-12T16:45:32.891Z"
            }
        }

    state: string

    the name of the state or region

    zip: string

    the postal code

    country: Date

    the name of the country

    lat: number

    the latitude coordinate of the address

    long: number

    the longitude coordinate of the address

    createdAt: Date

    account creation timestamp

    updatedAt: Date

    last update timestamp

    isDefault: boolean

    whether this is the default address

    funding: string

    funding type (credit, debit, etc.)

    UserAddress
    UserPayment
    SavedCard

    Catalog Filters

    A full reference to Liquid Commerce's Catalog API filters.

    Filter Parameters

    All the available options and parameters for filters when using the Catalog API to get catalog product data.

    Attribute
    Description

    key: string

    Available Filters

    Below are all the available filter key values that are available:

    • brands: Array<string>

    • flavor: Array<string>

    • region: Array<string

    Availability

    Attribute
    Description

    Engraving (deprecated, use )

    Attribute
    Description

    Binary

    Attribute
    Description

    Modalities

    Attribute
    Context

    Examples for the method parameters

    There are 3 different types allowed as acceptable values for the filters, object, array, string[]. Below are example of different type variation.

    categories: Array<string>

    price: object

    availability: string

    engraving: string

    fulfillment: Array<string>

    FilterSchema

    All the available filter properties received from catalog response, to be used in filtering results further on consequent catalog requests.

    Attribute
    Description

    FilterSchemaValue

    Attribute
    Description

    Sample catalog filters

    Catalog Filters Object
    >
  • variety: Array<string>

  • engraving: Engraving | Binary

  • fulfillment: Array<Modalities>

  • presale: Binary

  • tags: Array<string>

  • price: object

  • availability: Availability

  • categories: Array<Taxonomy>

  • sizes: Array<string>

  • colors: Array<string>

  • appellation: Array<string>

  • country: Array<string>

  • vintage: Array<string>

  • materials: Array<string>

  • collectionTags: Array<string>

  • The filter key to be applied (e.g., "tags", "price")

    values: string[] | object | string

    The values to filter by, type depends on the filter key

    AVAILABILITY_UNSPECIFIED: string

    Default value when availability is not specified

    IN_STOCK: string

    Products currently in stock

    OUT_OF_STOCK: string

    Products currently out of stock

    PREORDER: string

    Products available for pre-order

    BACKORDER: string

    Products available for back-order

    YES: string

    Products that can be engraved

    NO: string

    Products that cannot be engraved

    YES: string

    Represents a positive condition

    NO: string

    Represents a negative condition

    shipping: string

    Products available for shipping

    onDemand: string

    Products on demand

    bucket: string(Available Filters)

    filter key, ex: brands, availability, category

    values: Array<FilterSchemaValue>

    values, has 2 properties, value & count, ex:

    value: string

    filter option

    count: number

    matching items count

    Binary
    {
        "key": "categories",
        "values": [
            "SPIRITS > VODKA"
        ]
    }
    {
        "key": "price",
        // REQUIRED: at least, min or max
        // must be provided
        "values": {
            // OPTIONAL: if omitted, accounted for as 
            // negative to infinity
            "min": 5,
            // OPTIONAL: if omitted, accounted for as 
            // positive to infinity
            "max": 29
        }
    }
    {
        "key": "availability",
        // Available values: IN_STOCK | OUT_OF_STOCK
        "values": "IN_STOCK"
    }
    {
      "key": "engraving",
      "values": "YES"
    }
    jsonCopy{
      "key": "fulfillment",
      "values": ["onDemand"]
    }
    [
      {
        "bucket": "brands",
        "values": [
          {
            "value": "TITO'S",
            "count": 1
          }
        ]
      },
      {
        "bucket": "categories",
        "values": [
          {
            "value": "SPIRITS",
            "count": 1
          },
          {
            "value": "SPIRITS > VODKA",
            "count": 1
          }
        ]
      },
    ]
    {
    "filters": [
            {
                "key": "categories",
                "values": [
                    "SPIRITS > VODKA"
                ]
            },
            {
                "key": "price",
                "values": {
                    "min": 5,
                    "max": 38
                }
            },
            {
                "key": "availability",
                "values": "IN_STOCK"
            },
            {
                "key": "collectionTags",
                "values": [
                    "RESERVEBAR PICKS"
                ]
            }
        ],
    }

    Catalog

    A full reference to a catalog type for different Liquid Commerce APIs.

    CatalogType

    Attribute
    Description

    retailers: Array<>

    available retailers

    products: Array<>

    NavigationSchema

    Attribute
    Description

    CursorSchema

    Attribute
    Description

    Sample catalog

    Catalog Object

    Create/Update Cart

    Creates a new cart or updates an existing cart with items

    Endpoint Details

    POST /cart/update

    Get Order

    Gets order details using a reference ID (current system) or order number (previous system). Both identifiers are supported.

    Endpoint Details

    GET /orders/{identifier}

    total matching items

    availableOrderBy: Array<string>

    available sort fields

    availableOrderDirections: Array<string>

    sort directions

    cursor:

    pagination cursors

    filters:

    available filters

    matched products

    navigation: NavigationSchema

    navigation and filtering info

    id: string

    navigation session id

    correctedQuery: string

    spell-corrected search query

    attributionToken: string

    analytics tracking token

    currentPage: number

    current page number

    totalPages: number

    total available pages

    nextPageToken: string

    token for next page

    previousPageToken: string

    token for previous page

    Retailer
    Product

    totalCount: number

    Headers
    Header
    Value

    Content-Type

    application/json

    Authorization

    Bearer <YOUR_ACCESS_TOKEN>

    Body

    Parameter
    Type
    Description
    Required

    id

    string

    Cart ID (leave empty to create a new cart)

    items

    array<>

    Array of items to add to the cart

    loc

    Location object for determining availability and shipping

    Cart Update Item

    Parameter
    Type
    Description
    Required

    id

    string

    This parameter is REQUIRED when:

    • Updating any personalized configurations for a specific item in the cart (e.g., engraving messages, or other personalization options)

    • Deleting a product that has personalizations

    partNumber

    string

    Unique identifier for the retailer's product variant

    quantity

    number

    Quantity of the item

    Response Details

    Field
    Type
    Description

    statusCode

    number

    HTTP status code of the response

    message

    string

    A brief message describing the result of the API call

    metadata

    Contains metadata about the API call

    auth

    Authentication object, only when refresh in true

    Metadata Object

    Sample Request and Response

    Field
    Type
    Description
    Path Parameters
    Name
    Type
    Description
    Required

    identifier

    string

    Order ID, returned upon checkout complete

    Headers

    Header
    Value

    Content-Type

    application/json

    Authorization

    Bearer <YOUR_ACCESS_TOKEN>

    Response Details

    Field
    Type
    Description

    statusCode

    number

    HTTP status code of the response

    message

    string

    A brief message describing the result of the API call

    metadata

    Contains metadata about the API call

    data

    Order object

    Sample Request and Response

    Presales

    Presale Feature Guide

    Overview

    The LiquidCommerce SDK provides comprehensive support for presale products, allowing merchants to offer products for purchase before general availability. This guide covers how to integrate presale functionality into your application.

    What are Presales?

    Presales enable customers to reserve and purchase products before they become widely available. Key features include:

    • Advanced Purchase: Customers can buy products before stock arrival

    • Limited Quantities: Presale products often have purchase limits

    • Scheduled Availability: Products have defined presale windows

    • Exclusive Access: First-come, first-served inventory reservation

    Working with Presale Products

    Identifying Presale Products

    Use the catalog search to find presale products:

    Cart Response Structure

    When working with presale items, the cart response includes additional fields:

    Adding Presale Items to Cart

    Basic Implementation

    Handling Presale Events

    The SDK provides specific event types for presale scenarios:

    Example event handling:

    Checkout Process

    Preparing Checkout

    Complete the checkout process promptly when isPresaleLocked is true:

    Time-Sensitive Checkout

    Monitor the reservation time when dealing with presales:

    Best Practices

    1. Clear User Communication

    2. Cart Separation

    3. Error Recovery

    Common Integration Patterns

    Pattern 1: Presale Product Page

    Pattern 2: Presale Collection Page

    Limitations and Considerations

    System Limitations

    • Cart Exclusivity: Presale items require dedicated carts

    • Time Constraints: Reservations have expiration times

    • Quantity Restrictions: Limited inventory per customer

    • Geographic Availability: Some presales may be region-specific

    User Experience Considerations

    1. Transparency: Always show presale status and estimated shipping

    2. Urgency: Display reservation timers when applicable

    3. Clarity: Explain why presale items need separate orders

    4. Feedback: Provide clear error messages for presale-specific issues

    Summary

    The presale feature in LiquidCommerce SDK enables:

    • Early access to limited products

    • Automated inventory management

    • Time-based reservations

    • Clear event-driven feedback

    Successful presale integration requires careful attention to:

    • Event handling for various presale states

    • Time-sensitive checkout flows

    • Clear user communication

    • Proper cart segregation

    By following this guide and the provided examples, you can create a smooth presale experience that maximizes conversion while maintaining inventory integrity.

    Prepare

    Prepares a checkout session based on the provided cart and user information

    Endpoint Details

    POST /checkout/prepare

    Headers

    Header
    Value

    Body

    Parameter
    Type
    Description
    Required

    Response Details

    Field
    Type
    Description

    Metadata Object

    Sample Request and Response

    Availability

    Retrieves detailed product information and availability for specified UPCs based on location

    Endpoint Details

    POST /catalog/availability

     "products": [
            {
                "id": "ful_def456uvw123",
                "salsifyGrouping": "GRP-78392",
                "name": "Maestro Dobel® Diamante Tequila Cristalino",
                "brand": "Maestro Dobel",
                "catPath": "Spirits > Tequila > Cristalino",
                "category": "",
                "classification": "",
                "type": "",
                "subType": "",
                "region": "Jalisco",
                "country": "Mexico",
                "material": "Agave",
                "color": "White",
                "flavor": "",
                "variety": "100% Blue Agave",
                "appellation": "",
                "abv": "40",
                "proof": "80",
                "age": "",
                "vintage": "",
                "description": "Maestro Dobel® Diamante® is the original Cristalino. Blended extra Añejo, Añejo and reposado tequilas are aged in Balkan new white wood barrels, then filtered again to retain an elegant flavor. The Cristalino tequila has a mild oak aroma with a touch of vanilla. It has a citrus and prickly pear flavor with a smooth, crisp, clean finish. Pour one shot of straight Diamante Tequila to sip, into an old-fashioned glass with ice and a lemon slice, or as a Margarita. (80 proof)",
                "htmlDescription": "<p>Maestro Dobel® Diamante® is the original Cristalino. Blended extra Añejo, Añejo and reposado tequilas are aged in Balkan new white wood barrels, then filtered again to retain an elegant flavor. The Cristalino tequila has a mild oak aroma with a touch of vanilla. It has a citrus and prickly pear flavor with a smooth, crisp, clean finish. Pour one shot of straight Diamante Tequila to sip, into an old-fashioned glass with ice and a lemon slice, or as a Margarita. (80 proof)</p>",
                "tastingNotes": "World's first multi-aged clear tequila.",
                "images": [
                    "https://example.com/products/dobel-diamante-1.jpg",
                    "https://example.com/products/dobel-diamante-2.jpg"
                ],
                "sizes": [
                    {
                        "id": "sz_xy789zw456",
                        "upc": "00811538012034",
                        "size": "750 ML",
                        "volume": "750",
                        "uom": "MILLILITRE",
                        "container": "Bottle",
                        "containerType": "Bottle",
                        "pack": false,
                        "packDesc": "",
                        "image": "https://example.com/products/dobel-diamante-bottle.jpg",
                        "attributes": {
                            "engraving": {
                                "status": true,
                                "maxLines": 3,
                                "maxCharsPerLine": 16,
                                "fee": 5000,
                                "location": "Back of the Bottle"
                            }
                        }
                    }
                ]
            },
            {
                "id": "ful_ghi789rst123",
                "salsifyGrouping": "649066c19661fb45f6869934",
                "name": "The Macallan Double Cask 12 Years Old Single Malt Whisky",
                "brand": "The Macallan",
                "catPath": "Spirits > Whiskey > Scotch",
                "category": "",
                "classification": "",
                "type": "",
                "subType": "",
                "region": "Speyside",
                "country": "Scotland",
                "material": "Grain",
                "color": "Tawny/brown",
                "flavor": "",
                "variety": "Barley",
                "appellation": "Speyside",
                "abv": "40",
                "proof": "80",
                "age": "",
                "vintage": "",
                "description": "The Macallan Double Cask 12-Year-Old pairs the indulgent fruit, caramel, and oak spice character of Sherry-seasoned European oak with the bright citrus and vanilla notes of Sherry-seasoned American oak for a satisfyingly rich and perfectly balanced flavor experience. Awarded unanimous Double Gold upon release.",
                "htmlDescription": "<p>The Macallan Double Cask 12-Year-Old pairs the indulgent fruit, caramel, and oak spice character of Sherry-seasoned European oak with the bright citrus and vanilla notes of Sherry-seasoned American oak for a satisfyingly rich and perfectly balanced flavor experience. Awarded unanimous Double Gold upon release.</p>",
                "tastingNotes": "\"If there is royalty in the whisky world, it belongs to Scotland, and if there is a king of Scotch whisky, it's The Macallan.\" – Forbes",
                "images": [
                    "https://example.com/products/macallan-12-1.jpg"
                ],
                "sizes": [
                    {
                        "id": "sz_pqr123mn456",
                        "upc": "00812066021598",
                        "size": "750 ML",
                        "volume": "750",
                        "uom": "MILLILITRE",
                        "container": "Bottle",
                        "containerType": "Bottle",
                        "pack": false,
                        "packDesc": "",
                        "image": "https://example.com/products/macallan-12-bottle.jpg",
                        "attributes": {
                            "engraving": {
                                "status": true,
                                "maxLines": 3,
                                "maxCharsPerLine": 16,
                                "fee": 5000,
                                "location": "Below the Label"
                            }
                        }
                    }
                ]
            }
        ],
        "retailers": [
            {
                "id": "ret_abc123xyz789",
                "name": "LiquidCommerce Wine & Spirits",
                "platformFee": 499,
                "address": {
                    "one": "240 Loisaida Avenue",
                    "two": "",
                    "city": "New York",
                    "state": "NY",
                    "zip": "10009",
                    "country": "US"
                },
                "fulfillments": [
                    {
                        "id": "ful_ghi189rst123",
                        "timezone": "America/New_York",
                        "type": "onDemand",
                        "canEngrave": false,
                        "fees": {
                            "min": 1999,
                            "fee": 0,
                            "free": {
                                "active": false,
                                "min": 0
                            }
                        },
                        "expectation": {
                            "detail": "Arrives in 60 mins",
                            "short": "60 mins"
                        },
                        "hours": {
                            "monday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "10:00",
                                        "endsAt": "21:00"
                                    }
                                ]
                            },
                            "tuesday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "10:00",
                                        "endsAt": "21:00"
                                    }
                                ]
                            },
                            "wednesday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "10:00",
                                        "endsAt": "21:00"
                                    }
                                ]
                            },
                            "thursday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "10:00",
                                        "endsAt": "21:00"
                                    }
                                ]
                            },
                            "friday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "10:00",
                                        "endsAt": "21:00"
                                    }
                                ]
                            },
                            "saturday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "10:00",
                                        "endsAt": "21:00"
                                    }
                                ]
                            },
                            "sunday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "10:00",
                                        "endsAt": "21:00"
                                    }
                                ]
                            }
                        },
                        "breaks": [],
                        "items": []
                    }
                ]
            },
            {
                "id": "ret_abc123xyz189",
                "name": "LiquidCommerce Barn",
                "platformFee": 499,
                "address": {
                    "one": "1000 N 5th Ave",
                    "two": "134",
                    "city": "Vernon Hills",
                    "state": "NY",
                    "zip": "10061",
                    "country": "US"
                },
                "fulfillments": [
                    {
                        "id": "ful_abc123xyz189",
                        "timezone": "America/Chicago",
                        "type": "shipping",
                        "canEngrave": true,
                        "fees": {
                            "pack": {
                                "active": true,
                                "maxQuantity": 25,
                                "fee": 1599
                            },
                            "individual": {
                                "active": true,
                                "maxQuantity": 25,
                                "fee": 1599
                            },
                            "free": {
                                "active": false,
                                "min": 0
                            }
                        },
                        "expectation": {
                            "detail": "Ships in 2-3 days",
                            "short": "2-3 days"
                        },
                        "hours": {
                            "monday": {
                                "active": false,
                                "times": []
                            },
                            "tuesday": {
                                "active": false,
                                "times": []
                            },
                            "wednesday": {
                                "active": false,
                                "times": []
                            },
                            "thursday": {
                                "active": false,
                                "times": []
                            },
                            "friday": {
                                "active": false,
                                "times": []
                            },
                            "saturday": {
                                "active": false,
                                "times": []
                            },
                            "sunday": {
                                "active": false,
                                "times": []
                            }
                        },
                        "breaks": [],
                        "items": []
                    }
                ]
            }
        ]
    {
        "statusCode": 200,
        "message": "Create, build and manage carts.",
        "metadata": {
            "languages": [
                "en"
            ],
            "timestamp": 1731610845174,
            "timezone": "UTC",
            "requestId": "req_abc123xyz789",
            "path": "/api/cart/update",
            "version": "1.7.0"
        },
        "cart": {
            "id": "cart_abc123xyz789",
            "quantity": 1,
            "platformFee": 499,
            "deliveryFee": 0,
            "shippingFee": 1599,
            "engravingFee": 0,
            "discounts": 0,
            "giftCardTotal": 0,
            "subtotal": 5999,
            "total": 8097,
            "createdAt": "2024-11-14T19:00:45.433Z",
            "updatedAt": "2024-11-14T19:00:45.433Z",
            "items": [
                {
                    "id": "item_abc123xyz789",
                    "variantId": "var_abc123xyz789",
                    "liquidId": "liq_abc123xyz789",
                    "retailerId": "ret_abc123xyz789",
                    "partNumber": "pn_abc123xyz789",
                    "fulfillmentId": "ful_abc123xyz789",
                    "upc": "88320002003",
                    "catPath": "WINE > ROSE WINE",
                    "volume": "1.5",
                    "uom": "LITRE",
                    "pack": false,
                    "packDesc": "",
                    "container": "Bottle",
                    "containerType": "Bottle",
                    "name": "Whispering Angel Rosé",
                    "brand": "Chateau D'esclans",
                    "scheduledFor": "",
                    "abv": "14",
                    "proof": "28",
                    "size": "1.5 L",
                    "price": 5999,
                    "quantity": 1,
                    "customerPlacement": "standard",
                    "maxQuantity": 12,
                    "unitPrice": 5999,
                    "availableAt": "",
                    "mainImage": "https://storage.example.com/images/products/image1.png",
                    "images": [
                        "https://storage.example.com/images/products/image1.png",
                        "https://storage.example.com/images/products/image2.png",
                        "https://storage.example.com/images/products/image3.png",
                        "https://storage.example.com/images/products/image4.png",
                        "https://storage.example.com/images/products/image5.png"
                    ],
                    "attributes": {
                        "giftCard": {
                            "sender": "",
                            "message": "",
                            "recipients": [],
                            "sendDate": ""
                        },
                        "engraving": {
                            "isEngravable": true,
                            "hasEngraving": false,
                            "maxCharsPerLine": 0,
                            "maxLines": 0,
                            "fee": 0,
                            "location": "",
                            "lines": []
                        }
                    }
                }
            ],
            "loc": {
                "coords": {
                    "lat": 40.7447986,
                    "long": -73.98530819999999
                },
                "address": {
                    "one": "100 madison ave",
                    "two": "apt 1707",
                    "city": "New york",
                    "state": "NY",
                    "zip": "10016",
                    "country": "US",
                    "placesId": "place_abc123xyz789",
                    "customerId": "cust_abc123xyz789",
                    "type": "shipping",
                    "lat": 40.7447986,
                    "long": -73.98530819999999
                }
            },
            "retailers": [
                {
                    "id": "ret_abc123xyz789",
                    "name": "East Houston St Wine & Liquors",
                    "platformFee": 499,
                    "address": {
                        "one": "250 E Houston Street",
                        "two": "",
                        "city": "New York",
                        "state": "NY",
                        "zip": "10002",
                        "country": "US"
                    },
                    "fulfillments": [
                        {
                            "id": "ful_abc123xyz789",
                            "timezone": "America/New_York",
                            "type": "shipping",
                            "canEngrave": false,
                            "fees": {
                                "pack": {
                                    "active": true,
                                    "maxQuantity": 25,
                                    "fee": 1599
                                },
                                "individual": {
                                    "active": true,
                                    "maxQuantity": 25,
                                    "fee": 1599
                                },
                                "free": {
                                    "active": false,
                                    "min": 0
                                }
                            },
                            "expectation": {
                                "detail": "Ships in 2-3 days",
                                "short": "2-3 days"
                            },
                            "hours": {
                                "monday": {
                                    "active": false,
                                    "times": []
                                },
                                "tuesday": {
                                    "active": false,
                                    "times": []
                                },
                                "wednesday": {
                                    "active": false,
                                    "times": []
                                },
                                "thursday": {
                                    "active": false,
                                    "times": []
                                },
                                "friday": {
                                    "active": false,
                                    "times": []
                                },
                                "saturday": {
                                    "active": false,
                                    "times": []
                                },
                                "sunday": {
                                    "active": false,
                                    "times": []
                                }
                            },
                            "breaks": [],
                            "items": [
                                "item_abc123xyz789"
                            ],
                            "engravingFee": 0,
                            "shippingFee": 1599,
                            "deliveryFee": 0,
                            "subtotal": 5999
                        }
                    ],
                    "engravingFee": 0,
                    "deliveryFee": 0,
                    "shippingFee": 1599,
                    "subtotal": 5999,
                    "total": 8097
                }
            ],
            "attributes": {
                "promoCode": {
                    "value": "",
                    "freeDelivery": false,
                    "freeServiceFee": false,
                    "freeShipping": false
                },
                "amounts": {
                    "fees": {
                        "shipping": 5999,
                        "onDemand": 0
                    },
                    "discounts": {
                        "shipping": 0,
                        "onDemand": 0,
                        "engraving": 0,
                        "service": 0,
                        "products": 0
                    }
                }
            },
            "events": [
                {
                    "type": "NoId",
                    "message": "The cartId provided is empty, a new cart was created",
                    "items": []
                },
                {
                    "type": "PartnerProductConfigs",
                    "message": "Item(s) have been removed, they're currently not available in your account's catalog. Check your LiquidCommerce Partner App account and add the product to you account, or just use our default catalog",
                    "items": [
                        {
                            "partNumber": "pn_abc123xyz789",
                            "quantity": 1,
                            "fulfillmentId": "ful_abc123xyz789",
                            "id": "item_abc123xyz789"
                        }
                    ]
                }
            ]
        }
    }
    curl --location 'https://staging.api.liquidcommerce.cloud/cart/update' \
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
    --header 'Content-Type: application/json' \
    --data '{
        "id": "",
        "items": [
            {
                "partNumber": "partnum_123abc456def",
                "quantity": 1,
                "fulfillmentId": "65830af0be8824843febdb8f"
            },
            {
                "partNumber": "partnum_124abc456def",
                "quantity": 1,
                "engravingLines": [
                    "Happy birthday"
                ],
                "fulfillmentId": "65830af0be8824843febdb72"
            }
        ],
        "loc": {
            "address": {
                "one": "100 madison ave",
                "two": "apt 1707",
                "city": "New york",
                "state": "NY",
                "zip": "10016"
            }
        },
        "refresh": false
    }'
    curl --location 'https://staging.api.liquidcommerce.cloud/orders/order_number'
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>'
    {
        "statusCode": 200,
        "message": "Order fetched successfully.",
        "metadata": {
            "languages": [
                "en"
            ],
            "timestamp": 1745257267418,
            "timezone": "UTC",
            "requestId": "1deb1965-279b-4458-9b39-1baf83ca4fe7",
            "path": "/orders/1745257243084",
            "version": "1.7.0"
        },
        "data": {
            "referenceId": "RESV_90874794283742",
            "legacyOrderNumber": "174423423423423",
            "partnerId": "65ba4c2ea7f3d123456789ab",
            "createdAt": "2025-04-21T17:40:43.000Z",
            "updatedAt": "2025-04-21T17:40:49.000Z",
            "isHybrid": true,
            "customer": {
                "id": 12643699,
                "firstName": "Test",
                "lastName": "Test",
                "email": "[email protected]",
                "phone": "(432) 424-2424",
                "birthdate": "2004-04-21"
            },
            "addresses": {
                "shipping": {
                    "one": "100 Madison Avenue",
                    "two": null,
                    "city": "Morristown",
                    "state": "NJ",
                    "zip": "07960",
                    "country": "US",
                    "firstName": "Test",
                    "lastName": "Test",
                    "email": "[email protected]",
                    "phone": "(432) 424-2424",
                    "company": null
                },
                "billing": {
                    "one": "100 Madison Avenue",
                    "two": null,
                    "city": "Morristown",
                    "state": "NJ",
                    "zip": "07960",
                    "country": "US",
                    "firstName": "Test",
                    "lastName": "Test",
                    "email": "[email protected]",
                    "phone": "(432) 424-2424",
                    "company": null
                }
            },
            "options": {
                "isGift": false,
                "giftMessage": null,
                "giftRecipient": {
                    "name": null,
                    "email": null,
                    "phone": null
                },
                "hasVerifiedAge": false,
                "allowsSubstitution": true,
                "billingSameAsShipping": true,
                "deliveryInstructions": null,
                "marketingPreferences": {
                    "email": true,
                    "sms": true
                }
            },
            "amounts": {
                "subtotal": 8638,
                "shipping": 1998,
                "platform": 1198,
                "tax": 704,
                "engraving": 0,
                "service": 0,
                "delivery": 0,
                "discounts": 0,
                "giftCards": 0,
                "tip": 0,
                "total": 12538,
                "taxDetails": {
                    "products": 572,
                    "shipping": 132,
                    "delivery": 0,
                    "bag": 0,
                    "bottleDeposits": 0,
                    "retailDelivery": 0
                },
                "discountDetails": {
                    "products": 0,
                    "shipping": 0,
                    "delivery": 0,
                    "engraving": 0,
                    "service": 0
                }
            },
            "paymentMethods": [
                {
                    "type": "CREDIT_CARD",
                    "card": "Visa",
                    "last4": "1111",
                    "holder": "Test Test",
                    "code": null
                }
            ],
            "retailers": [
                {
                    "id": "65ba4d9f1234567890abcdef",
                    "legacyId": "1798987",
                    "name": "Test Liquor & Wine Cellar",
                    "system": "ReserveBar OMS",
                    "timezone": "America/Chicago",
                    "address": {
                        "one": "6506 Liquor Test",
                        "two": "Suite 800",
                        "city": "Sugar Land",
                        "state": "NY",
                        "zip": "10019",
                        "country": "US",
                        "coordinates": {
                            "latitude": 29.6079351,
                            "longitude": -95.6592685
                        }
                    },
                    "fulfillments": [
                        {
                            "id": "65ba4db8abcdef1234567890",
                            "type": "shipping",
                            "status": "processing",
                            "scheduledFor": null,
                            "updatedAt": "2025-04-21T17:40:49.000Z",
                            "itemIds": [
                                "f47ac10b-58cc-4372-a567-0e02b2c3d479"
                            ],
                            "packages": [],
                            "timeline": [
                                {
                                    "status": "processing",
                                    "timestamp": "2025-04-21T17:40:49.91184"
                                },
                                {
                                    "status": "created",
                                    "timestamp": "2025-04-21T17:40:45.711992"
                                }
                            ]
                        }
                    ],
                    "amounts": {
                        "subtotal": 4139,
                        "shipping": 999,
                        "platform": 0,
                        "tax": 340,
                        "engraving": 0,
                        "service": 0,
                        "delivery": 0,
                        "discounts": 0,
                        "giftCards": 0,
                        "tip": 0,
                        "total": 5478,
                        "taxDetails": {
                            "products": 274,
                            "shipping": 66,
                            "delivery": 0,
                            "bag": 0,
                            "bottleDeposits": 0,
                            "retailDelivery": 0
                        },
                        "discountDetails": {
                            "products": 0,
                            "shipping": 0,
                            "delivery": 0,
                            "engraving": 0,
                            "service": 0
                        }
                    }
                },
                {
                    "id": "65ba4df09876543210fedcba",
                    "legacyId": "89928",
                    "name": "Liquid's Elixir & Spirits",
                    "system": "ReserveBar OMS",
                    "timezone": "America/New_York",
                    "address": {
                        "one": "2627 Main Ave NW",
                        "two": null,
                        "city": "Dalton",
                        "state": "NC",
                        "zip": "20008",
                        "country": "US",
                        "coordinates": {
                            "latitude": 38.924376,
                            "longitude": -77.0515667
                        }
                    },
                    "fulfillments": [
                        {
                            "id": "65ba4e0812345678abcdef90",
                            "type": "shipping",
                            "status": "created",
                            "scheduledFor": null,
                            "updatedAt": "2025-04-21T17:40:45.000Z",
                            "itemIds": [
                                "d0782bd8-86c8-4053-93b5-a48a28f5648b"
                            ],
                            "packages": [],
                            "timeline": [
                                {
                                    "status": "created",
                                    "timestamp": "2025-04-21T17:40:45.749774"
                                }
                            ]
                        }
                    ],
                    "amounts": {
                        "subtotal": 4499,
                        "shipping": 999,
                        "platform": 0,
                        "tax": 364,
                        "engraving": 0,
                        "service": 0,
                        "delivery": 0,
                        "discounts": 0,
                        "giftCards": 0,
                        "tip": 0,
                        "total": 5862,
                        "taxDetails": {
                            "products": 298,
                            "shipping": 66,
                            "delivery": 0,
                            "bag": 0,
                            "bottleDeposits": 0,
                            "retailDelivery": 0
                        },
                        "discountDetails": {
                            "products": 0,
                            "shipping": 0,
                            "delivery": 0,
                            "engraving": 0,
                            "service": 0
                        }
                    }
                }
            ],
            "items": [
                {
                    "id": "d0782bd8-86c8-4053-93b5-a48a28f5648b",
                    "fulfillmentId": "65ba4f2312345678abcdef90",
                    "retailerId": "65ba4f359876543210fedcba",
                    "variantId": "65ba4f5712345678fedcba09",
                    "liquidId": "65ba4f40abcdef1234567890",
                    "legacyGrouping": null,
                    "legacyPid": "pid-abc",
                    "customerPlacement": "standard",
                    "isPresale": false,
                    "estimatedShipBy": null,
                    "product": {
                        "name": "Liquid Elixir",
                        "brand": "Liquid",
                        "upc": "001928391838291",
                        "sku": "958050",
                        "mskus": [
                            "LIQUID-ELIXIR"
                        ],
                        "category": "SPIRITS > MEZCAL",
                        "size": "700 ML",
                        "volume": "700",
                        "uom": "ML",
                        "proof": null,
                        "attributes": {
                            "pack": false,
                            "packDescription": null,
                            "abv": "43",
                            "container": "BOTTLE",
                            "containerType": "Bottle"
                        }
                    },
                    "image": "https://assets.liquidcommerce.co/core/white_matte_bottle_nobg.png",
                    "pricing": {
                        "price": 4139,
                        "unitPrice": 4139,
                        "quantity": 1,
                        "tax": 274,
                        "bottleDeposits": 0
                    },
                    "attributes": {
                        "engraving": {
                            "hasEngraving": false,
                            "fee": 0,
                            "location": null,
                            "lines": []
                        },
                        "giftCard": {
                            "sender": null,
                            "message": null,
                            "recipients": [],
                            "sendDate": null
                        }
                    }
                },
                {
                    "id": "33b5e5a7-5dd7-4e33-b8a8-5cf7cec79f39",
                    "fulfillmentId": "65ba501eedcba0987654321f",
                    "retailerId": "65ba501eedcba0987654321f",
                    "variantId": "65ba501eedcba0987654321f",
                    "liquidId": "65ba501eedcba0987654321f",
                    "legacyGrouping": "GROUPING-123456",
                    "legacyPid": "pid-abc",
                    "customerPlacement": "standard",
                    "isPresale": false,
                    "estimatedShipBy": null,
                    "product": {
                        "name": "Liquid Elixir Aged",
                        "brand": "Liquid",
                        "upc": "001928391838291",
                        "sku": "65ba4f9210fedcba98765432_65ba501eedcba0987654321f",
                        "mskus": [
                            "LIQUID-ELIXIR-AGED"
                        ],
                        "category": "SPIRITS > WHISKEY > BOURBON",
                        "size": "750 ML",
                        "volume": "750",
                        "uom": "ML",
                        "proof": null,
                        "attributes": {
                            "pack": false,
                            "packDescription": null,
                            "abv": "40",
                            "container": "BOTTLE",
                            "containerType": "Bottle"
                        }
                    },
                    "image": "https://assets.liquidcommerce.co/core/white_matte_bottle_nobg.png",
                    "pricing": {
                        "price": 4499,
                        "unitPrice": 4499,
                        "quantity": 1,
                        "tax": 298,
                        "bottleDeposits": 0
                    },
                    "attributes": {
                        "engraving": {
                            "hasEngraving": false,
                            "fee": 5000,
                            "location": "Side of the Bottle",
                            "lines": []
                        },
                        "giftCard": {
                            "sender": null,
                            "message": null,
                            "recipients": [],
                            "sendDate": null
                        }
                    }
                }
            ]
        }
    }
    CursorSchema
    FilterSchema
    metaDataObject
    orderType

    path

    string

    API path

    version

    string

    API version used for the request

    promoCode

    string

    Promotional code to apply to the cart

    isLegacy

    boolean

    Whether to return legacy identifiers

    refresh

    boolean

    When true, a new access token will be generated

    fulfillmentId

    string

    ID of the retailer's fulfillment method

    engravingLines

    array<string>

    Array of engraving text lines (if applicable)

    scheduledFor

    string

    ISO date string for scheduled delivery (onDemand only)

    sku

    string

    Product SKU

    cart

    cartType

    Cart details

    languages

    Array<string>

    List of supported languages for the response, e.g. ["en"]

    timestamp

    string

    Unix timestamp (in milliseconds) when the response was generated

    timezone

    string

    Timezone used for the response, always "UTC"

    requestId

    string

    cartUpdateItem
    locType
    metaDataObject
    authObject

    Unique identifier for the API request. Used for debugging and support

    const presaleProducts = await liquidCommerce.catalog.search({
      filters: [{
        key: ENUM_FILTER_KEYS.PRESALE,
        values: ENUM_BINARY_FILTER.YES
      }],
      loc: {
        address: {
          one: '123 Main St',
          city: 'New York',
          state: 'NY',
          zip: '10001'
        }
      }
    });
    
    // Extract presale information from products
    presaleProducts.products.forEach(product => {
      product.sizes.forEach(size => {
        const presale = size.attributes?.presale;
        if (presale?.isActive) {
          console.log({
            product: product.name,
            availableFrom: presale.canPurchaseOn,
            estimatedShipping: presale.estimatedShipBy,
            status: 'Active Presale'
          });
        }
      });
    });
    interface ICart {
      id: string;
      // ... standard cart fields
      
      // Presale-specific fields
      isPresaleLocked: boolean;        // Indicates cart contains presale items
      presaleExpiresAt: string | null; // Reservation expiration time
      
      events: ICartEvent[];            // Contains presale-related events
    }
    const cartResponse = await liquidCommerce.cart.update({
      id: cartId, // Use existing cart ID or create new
      items: [{
        partNumber: 'WHISKEY_PRESALE_2024_retailer_abc',
        quantity: 1,
        fulfillmentId: 'shipping_fulfillment_123'
      }],
      loc: {
        address: {
          one: '456 Oak Avenue',
          city: 'Los Angeles',
          state: 'CA',
          zip: '90001'
        }
      }
    });
    
    // Check if presale was successfully added
    if (cartResponse.isPresaleLocked) {
      console.log('Presale item reserved successfully');
      console.log(`Complete checkout by: ${cartResponse.presaleExpiresAt}`);
    }
    // Available presale events
    enum CART_EVENT_ENUM {
      PRESALE_ITEMS_NOT_ALLOWED = 'PresaleItemsNotAllowed',
      PRESALE_LIMIT_EXCEEDED = 'PresaleLimitExceeded',
      PRESALE_NOT_STARTED = 'PresaleNotStarted',
      PRESALE_EXPIRED = 'PresaleExpired',
      PRESALE_MIXED_CART = 'PresaleMixedCart',
    }
    function handlePresaleEvents(cart: ICart) {
      cart.events.forEach(event => {
        switch(event.type) {
          case CART_EVENT_ENUM.PRESALE_NOT_STARTED:
            // Presale hasn't begun yet
            alert('This presale has not started. Please check back later.');
            break;
            
          case CART_EVENT_ENUM.PRESALE_LIMIT_EXCEEDED:
            // Requested quantity exceeds available inventory
            alert('Sorry, not enough inventory available. Please try a smaller quantity.');
            break;
            
          case CART_EVENT_ENUM.PRESALE_EXPIRED:
            // Presale period has ended
            alert('This presale has ended.');
            break;
            
          case CART_EVENT_ENUM.PRESALE_MIXED_CART:
            // Cannot mix presale with other items
            alert('Presale items must be purchased separately.');
            break;
        }
      });
    }
    async function checkoutPresaleCart(cartId: string) {
      // Step 1: Prepare checkout
      const checkoutPrep = await liquidCommerce.checkout.prepare({
        cartId: cartId,
        customer: {
          firstName: "Sarah",
          lastName: "Johnson",
          email: "[email protected]",
          phone: "3105551234",
          birthDate: "1985-06-15"
        },
        billingAddress: {
          firstName: "Sarah",
          lastName: "Johnson",
          email: "[email protected]",
          phone: "3105551234",
          one: "789 Pine Street",
          two: "Suite 100",
          city: "San Francisco",
          state: "CA",
          zip: "94102"
        },
        hasSubstitutionPolicy: true,
        marketingPreferences: {
          canEmail: true,
          canSms: false
        }
      });
    
      // Step 2: Process payment
      // Assuming payment element is already mounted
      const paymentToken = await liquidCommerce.payment.generateToken();
      
      if ('id' in paymentToken) {
        // Step 3: Complete checkout
        const order = await liquidCommerce.checkout.complete({
          token: checkoutPrep.token,
          payment: paymentToken.id
        });
        
        return order;
      }
    }
    class PresaleCheckoutManager {
      private expirationTimer?: NodeJS.Timeout;
      
      startCheckout(cart: ICart) {
        if (!cart.isPresaleLocked || !cart.presaleExpiresAt) {
          return;
        }
        
        const expiresAt = new Date(cart.presaleExpiresAt);
        const now = new Date();
        const timeRemaining = expiresAt.getTime() - now.getTime();
        
        // Show countdown to user
        this.displayCountdown(timeRemaining);
        
        // Warn before expiration
        if (timeRemaining > 60000) { // More than 1 minute
          this.expirationTimer = setTimeout(() => {
            this.warnUserAboutExpiration();
          }, timeRemaining - 60000);
        }
      }
      
      private displayCountdown(milliseconds: number) {
        const minutes = Math.floor(milliseconds / 60000);
        const seconds = Math.floor((milliseconds % 60000) / 1000);
        console.log(`Time remaining: ${minutes}:${seconds.toString().padStart(2, '0')}`);
      }
      
      private warnUserAboutExpiration() {
        alert('Your presale reservation expires in 1 minute!');
      }
      
      cleanup() {
        if (this.expirationTimer) {
          clearTimeout(this.expirationTimer);
        }
      }
    }
    // Display presale information prominently
    function displayPresaleInfo(product: IProduct) {
      const presaleInfo = product.sizes[0]?.attributes?.presale;
      
      if (presaleInfo?.isActive) {
        return {
          status: 'PRESALE',
          availableDate: presaleInfo.canPurchaseOn,
          shippingDate: presaleInfo.estimatedShipBy,
          message: `Pre-order now, ships ${formatDate(presaleInfo.estimatedShipBy)}`
        };
      }
    }
    // Check before adding items to existing cart
    async function addToCart(item: ICartUpdateItem, existingCartId?: string) {
      if (existingCartId) {
        // Check if existing cart has presale items
        const existingCart = await liquidCommerce.cart.get(existingCartId);
        
        if (existingCart.isPresaleLocked) {
          // Create new cart for non-presale items
          console.log('Creating new cart - existing cart contains presale items');
          return await liquidCommerce.cart.update({
            id: 'new',
            items: [item],
            loc: existingCart.loc
          });
        }
      }
      
      // Safe to use existing cart
      return await liquidCommerce.cart.update({
        id: existingCartId || 'new',
        items: [item],
        loc: { /* location */ }
      });
    }
    async function robustPresalePurchase(
      partNumber: string,
      quantity: number,
      maxRetries: number = 3
    ) {
      let attempts = 0;
      
      while (attempts < maxRetries) {
        try {
          const cart = await liquidCommerce.cart.update({
            id: 'new',
            items: [{ partNumber, quantity, fulfillmentId: 'shipping_123' }],
            loc: { /* location */ }
          });
          
          // Check for presale events
          const hasPresaleError = cart.events.some(e => 
            e.type === CART_EVENT_ENUM.PRESALE_LIMIT_EXCEEDED ||
            e.type === CART_EVENT_ENUM.PRESALE_EXPIRED
          );
          
          if (hasPresaleError) {
            throw new Error('Presale not available');
          }
          
          if (cart.isPresaleLocked) {
            return { success: true, cart };
          }
          
        } catch (error) {
          attempts++;
          if (attempts >= maxRetries) {
            return { success: false, error: error.message };
          }
          // Wait before retry
          await new Promise(resolve => setTimeout(resolve, 1000));
        }
      }
    }
    class PresaleProductPage {
      async displayProduct(productId: string) {
        // Fetch product details
        const availability = await liquidCommerce.catalog.availability({
          ids: [productId],
          loc: this.getUserLocation()
        });
        
        const product = availability.products[0];
        const presaleSize = product.sizes.find(s => 
          s.attributes?.presale?.isActive
        );
        
        if (presaleSize) {
          this.showPresaleBadge();
          this.showEstimatedShipping(presaleSize.attributes.presale.estimatedShipBy);
          this.enablePresalePurchase(presaleSize);
        }
      }
      
      private async enablePresalePurchase(size: IProductSize) {
        // Set up purchase button
        const purchaseButton = document.getElementById('purchase-btn');
        purchaseButton.onclick = async () => {
          const cart = await liquidCommerce.cart.update({
            id: 'new',
            items: [{
              partNumber: size.variants[0].partNumber,
              quantity: 1,
              fulfillmentId: size.variants[0].fulfillments[0]
            }],
            loc: this.getUserLocation()
          });
          
          if (cart.isPresaleLocked) {
            // Redirect to checkout
            window.location.href = `/checkout?cartId=${cart.id}`;
          }
        };
      }
    }
    async function createPresaleCollection() {
      // Fetch all active presales
      const presales = await liquidCommerce.catalog.search({
        filters: [{
          key: ENUM_FILTER_KEYS.PRESALE,
          values: ENUM_BINARY_FILTER.YES
        }],
        orderBy: ENUM_ORDER_BY.PRICE,
        orderDirection: ENUM_NAVIGATION_ORDER_DIRECTION_TYPE.ASC,
        page: 1,
        perPage: 20,
        loc: { /* user location */ }
      });
      
      // Group by availability date
      const groupedPresales = presales.products.reduce((acc, product) => {
        product.sizes.forEach(size => {
          const presale = size.attributes?.presale;
          if (presale?.isActive && presale.canPurchaseOn) {
            const date = new Date(presale.canPurchaseOn).toDateString();
            if (!acc[date]) acc[date] = [];
            acc[date].push({ product, size });
          }
        });
        return acc;
      }, {});
      
      return groupedPresales;
    }

    hasSubstitutionPolicy

    boolean

    Whether substitution policy is accepted

    isGift

    boolean

    When the order is set as gift (isGift is set to true), the system adds gift messaging, special packaging, and gift receipts with optional sender anonymity

    hasAgeVerify

    boolean

    Should the checkout verify age

    billingSameAsShipping

    boolean

    Whether billing address is same as shipping

    giftOptions

    Gift options if applicable

    marketingPreferences

    Marketing preferences

    deliveryTips

    array<>

    Array of delivery tip objects

    deliveryInstructions

    array<>

    Delivery instructions for on-demand orders only

    shippingAddressTwo

    string

    Optional second line for the shipping address

    acceptedAccountCreation

    boolean

    Whether customer accepted account creation

    scheduledDelivery

    string

    Scheduled delivery datetime (ISO format)

    payment

    string

    Payment method identifier

    promoCode

    string

    Promotional code to apply a discount to the checkout

    giftCards

    array<string>

    Array of gift card codes to apply as payment methods

    isLegacy

    boolean

    Whether to return legacy identifiers

    refresh

    boolean

    When set to true, a new access token will be generated and returned

    checkout

    Checkout type

    Content-Type

    application/json

    Authorization

    Bearer <YOUR_ACCESS_TOKEN>

    cartId

    string

    ID of the cart to checkout

    customer

    customer

    Customer information

    billingAddress

    billingAddress

    Billing address details

    statusCode

    number

    Internal status code of the response

    message

    string

    A brief message describing the result of the API call

    metadata

    metaDataObject

    Contains metadata about the API call

    auth

    authObject

    Authentication object, only when refresh in true

    Field
    Type
    Description

    languages

    Array<string>

    List of supported languages for the response, e.g. ["en"]

    timestamp

    string

    Unix timestamp (in milliseconds) when the response was generated

    timezone

    string

    Timezone used for the response, always "UTC"

    requestId

    string

    Headers
    Header
    Value

    Content-Type

    application/json

    Authorization

    Bearer <YOUR_ACCESS_TOKEN>

    Body

    Parameter
    Type
    Description
    Required

    upcs

    array<string>

    Array of UPCs to check availability. Maximum: 70 UPCs

    grouping

    array<string>

    Array of grouping IDs to check availability. Maximum: 70 grouping IDs

    ids

    array<string>

    Array of product IDs to check availability. Maximum: 70 IDs

    At least one of upcs, grouping, or ids must be provided.

    Response Details

    Field
    Type
    Description

    statusCode

    number

    HTTP status code of the response

    message

    string

    A brief message describing the result of the API call

    metadata

    Contains metadata about the API call

    auth

    Authentication object, only when refresh in true

    Metadata Object

    Sample Request and Response

    Field
    Type
    Description

    Details

    Provides address suggestions based on user input

    Endpoint Details

    POST /address/details

    Headers

    Header
    Value

    Body

    Parameter
    Type
    Description
    Required

    Response Details

    Field
    Type
    Description

    Metadata Object

    Address Object

    Field
    Type
    Description

    Address Type Object

    Field
    Type
    Description

    Sample Request and Response

    Retailer

    A full reference to a retailer type for different Liquid Commerce APIs.

    RetailerType

    Attribute
    Description
    curl --location 'https://staging.api.liquidcommerce.cloud/checkout/prepare' \
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
    --header 'Content-Type: application/json' \
    --data-raw '{
        "cartId": "cart_abc123xyz789", // create a new cart
        "customer": {
            "firstName": "Joe",
            "lastName": "John",
            "email": "[email protected]",
            "phone": "9732119920",
            "birthDate": "11-22-1998",
            "hasAgeVerify": true
        },
        "billingAddress": {
            "firstName": "NewJoe",
            "lastName": "NewJohn",
            "email": "[email protected]",
            "phone": "1234324987",
            "one": "22 Washington Ave",
            "two": "",
            "city": "Cliffside Park",
            "state": "NJ",
            "zip": "07010"
        },
        "hasSubstitutionPolicy": true,
        "isGift": false,
        "billingSameAsShipping": true,
        "giftOptions": {
            "message": "",
            "recipient": {
                "name": "",
                "phone": "",
                "email": ""
            }
        },
        "marketingPreferences": {
            "canEmail": true,
            "canSms": true
        },
        "deliveryTips": [
            {
                "fulfillmentId": "6570c3ec700628ce1910c105",
                "tip": 2500
            }
        ],
        "refresh": true
    }'
    {
        "statusCode": 200,
        "message": "Prepare a checkout prior to processing.",
        "metadata": {
            "languages": [
                "en"
            ],
            "timestamp": 1731613340101,
            "timezone": "UTC",
            "requestId": "req_abc123xyz789",
            "path": "/api/checkout/prepare",
            "version": "1.7.0"
        },
        "auth": {
            "token": "auth_token_abc123xyz789",
            "type": "ACCESS_TOKEN",
            "exp": 1731679155851
        },
        "checkout": {
            "token": "checkout_token_abc123xyz789",
            "cartId": "cart_abc123xyz789",
            "customer": {
                "id": "usr_abc123xyz789",
                "email": "[email protected]",
                "firstName": "John",
                "company": "",
                "lastName": "Doe",
                "phone": "(555) 555-5555",
                "profileImage": "",
                "birthDate": "1998-11-22T00:00:00.000Z",
                "createdAt": "2024-11-14T19:13:34.231Z",
                "updatedAt": "2024-11-14T19:42:20.314Z"
            },
            "createdAt": "2024-11-14T19:13:35.004Z",
            "updatedAt": "2024-11-14T19:42:20.420Z",
            "hasAgeVerify": false,
            "hasSubstitutionPolicy": true,
            "acceptedAccountCreation": false,
            "isGift": false,
            "billingSameAsShipping": true,
            "giftOptions": {
                "message": "",
                "recipient": {
                    "name": "",
                    "email": "",
                    "phone": ""
                }
            },
            "marketingPreferences": {
                "canEmail": true,
                "canSms": true
            },
            "shippingAddress": {
                "one": "100 madison ave",
                "two": "",
                "city": "New york",
                "state": "NY",
                "zip": "10016",
                "country": "US"
            },
            "billingAddress": {
                "one": "100 madison ave",
                "two": "",
                "city": "New york",
                "state": "NY",
                "zip": "10016",
                "email": "[email protected]",
                "country": "US",
                "firstName": "John",
                "lastName": "Doe",
                "company": "",
                "phone": "(555) 555-5555"
            },
            "amounts": {
                "subtotal": 5999,
                "engraving": 0,
                "service": 0,
                "shipping": 1599,
                "delivery": 0,
                "platform": 499,
                "discounts": 0,
                "giftCards": 0,
                "tax": 684,
                "tip": 0,
                "total": 8781,
                "details": {
                    "discounts": {
                        "products": 0,
                        "delivery": 0,
                        "shipping": 0,
                        "engraving": 0,
                        "service": 0
                    },
                    "taxes": {
                        "bag": 5,
                        "bottleDeposits": 5,
                        "retailDelivery": 0,
                        "products": 532,
                        "delivery": 0,
                        "shipping": 142
                    }
                }
            },
            "items": [
                {
                    "variantId": "var_abc123xyz789",
                    "liquidId": "liq_abc123xyz789",
                    "cartItemId": "item_abc123xyz789",
                    "retailerId": "ret_abc123xyz789",
                    "fulfillmentId": "ful_abc123xyz789",
                    "name": "Whispering Angel Rosé",
                    "brand": "Chateau D'esclans",
                    "mainImage": "https://storage.example.com/images/products/image1.png",
                    "image": "https://storage.example.com/images/products/image1.png",
                    "size": "1.5 L",
                    "pack": false,
                    "packDesc": "",
                    "volume": "1.5",
                    "uom": "LITRE",
                    "abv": "14",
                    "containerType": "Bottle",
                    "container": "Bottle",
                    "partNumber": "88320002003_ret_abc123xyz789",
                    "upc": "88320002003",
                    "catPath": "WINE > ROSE WINE",
                    "customerPlacement": "standard",
                    "price": 5999,
                    "unitPrice": 5999,
                    "quantity": 1,
                    "attributes": {
                        "giftCard": {
                            "sender": "",
                            "message": "",
                            "recipients": [],
                            "sendDate": ""
                        },
                        "engraving": {
                            "isEngravable": true,
                            "hasEngraving": false,
                            "maxCharsPerLine": 0,
                            "maxLines": 0,
                            "fee": 0,
                            "location": "",
                            "lines": []
                        }
                    },
                    "bottleDeposits": 5,
                    "tax": 532
                }
            ],
            "retailers": [
                {
                    "id": "ret_abc123xyz789",
                    "name": "East Houston St Wine & Liquors",
                    "address": {
                        "one": "250 E Houston Street",
                        "two": "",
                        "city": "New York",
                        "state": "NY",
                        "zip": "10002",
                        "country": "US"
                    },
                    "subtotal": 5999,
                    "engraving": 0,
                    "service": 0,
                    "shipping": 1599,
                    "delivery": 0,
                    "platform": 499,
                    "discounts": 0,
                    "giftCards": 0,
                    "tax": 684,
                    "tip": 0,
                    "total": 8781,
                    "details": {
                        "discounts": {
                            "products": 0,
                            "delivery": 0,
                            "shipping": 0,
                            "engraving": 0,
                            "service": 0
                        },
                        "taxes": {
                            "bag": 5,
                            "bottleDeposits": 5,
                            "retailDelivery": 0,
                            "products": 532,
                            "delivery": 0,
                            "shipping": 142
                        }
                    },
                    "fulfillments": [
                        {
                            "id": "ful_abc123xyz789",
                            "scheduledFor": "",
                            "type": "shipping",
                            "expectation": {
                                "detail": "Ships in 2-3 days",
                                "short": "2-3 days"
                            },
                            "subtotal": 5999,
                            "engraving": 0,
                            "service": 0,
                            "shipping": 1599,
                            "delivery": 0,
                            "discounts": 0,
                            "giftCards": 0,
                            "tip": 0,
                            "items": [
                                "item_abc123xyz789"
                            ],
                            "total": 8282,
                            "details": {
                                "discounts": {
                                    "products": 0,
                                    "delivery": 0,
                                    "shipping": 0,
                                    "engraving": 0,
                                    "service": 0
                                },
                                "taxes": {
                                    "bag": 5,
                                    "bottleDeposits": 5,
                                    "retailDelivery": 0,
                                    "products": 532,
                                    "delivery": 0,
                                    "shipping": 142
                                }
                            },
                            "tax": 684
                        }
                    ]
                }
            ],
            "payment": ""
        }
    }
    {
        "statusCode": 200,
        "message": "List of available products based on upcs provided.",
        "metadata": {
            "languages": [
                "en"
            ],
            "timestamp": 1731607501591,
            "timezone": "UTC",
            "requestId": "requestid_123abc456def",
            "path": "/api/catalog/availability",
            "version": "1.7.0"
        },
        "products": [
            {
                "id": "ful_def456uvw123",
                "salsifyGrouping": "GRP-78392",
                "name": "Maestro Dobel® Diamante Tequila Cristalino",
                "brand": "Maestro Dobel",
                "catPath": "Spirits > Tequila > Cristalino",
                "category": "",
                "classification": "",
                "type": "",
                "subType": "",
                "region": "Jalisco",
                "country": "Mexico",
                "material": "Agave",
                "color": "White",
                "flavor": "",
                "variety": "100% Blue Agave",
                "appellation": "",
                "abv": "40",
                "proof": "80",
                "age": "",
                "vintage": "",
                "description": "Maestro Dobel® Diamante® is the original Cristalino. Blended extra Añejo, Añejo and reposado tequilas are aged in Balkan new white wood barrels, then filtered again to retain an elegant flavor. The Cristalino tequila has a mild oak aroma with a touch of vanilla. It has a citrus and prickly pear flavor with a smooth, crisp, clean finish. Pour one shot of straight Diamante Tequila to sip, into an old-fashioned glass with ice and a lemon slice, or as a Margarita. (80 proof)",
                "htmlDescription": "<p>Maestro Dobel® Diamante® is the original Cristalino. Blended extra Añejo, Añejo and reposado tequilas are aged in Balkan new white wood barrels, then filtered again to retain an elegant flavor. The Cristalino tequila has a mild oak aroma with a touch of vanilla. It has a citrus and prickly pear flavor with a smooth, crisp, clean finish. Pour one shot of straight Diamante Tequila to sip, into an old-fashioned glass with ice and a lemon slice, or as a Margarita. (80 proof)</p>",
                "tastingNotes": "World's first multi-aged clear tequila.",
                "images": [
                    "https://example.com/products/dobel-diamante-1.jpg",
                    "https://example.com/products/dobel-diamante-2.jpg"
                ],
                "sizes": [
                    {
                        "id": "sz_xy789zw456",
                        "upc": "00811538012034",
                        "size": "750 ML",
                        "volume": "750",
                        "uom": "MILLILITRE",
                        "container": "Bottle",
                        "containerType": "Bottle",
                        "pack": false,
                        "packDesc": "",
                        "image": "https://example.com/products/dobel-diamante-bottle.jpg",
                        "attributes": {
                            "engraving": {
                                "status": true,
                                "maxLines": 3,
                                "maxCharsPerLine": 16,
                                "fee": 5000,
                                "location": "Back of the Bottle"
                            }
                        }
                    }
                ]
            },
            {
                "id": "ful_ghi789rst123",
                "salsifyGrouping": "649066c19661fb45f6869934",
                "name": "The Macallan Double Cask 12 Years Old Single Malt Whisky",
                "brand": "The Macallan",
                "catPath": "Spirits > Whiskey > Scotch",
                "category": "",
                "classification": "",
                "type": "",
                "subType": "",
                "region": "Speyside",
                "country": "Scotland",
                "material": "Grain",
                "color": "Tawny/brown",
                "flavor": "",
                "variety": "Barley",
                "appellation": "Speyside",
                "abv": "40",
                "proof": "80",
                "age": "",
                "vintage": "",
                "description": "The Macallan Double Cask 12-Year-Old pairs the indulgent fruit, caramel, and oak spice character of Sherry-seasoned European oak with the bright citrus and vanilla notes of Sherry-seasoned American oak for a satisfyingly rich and perfectly balanced flavor experience. Awarded unanimous Double Gold upon release.",
                "htmlDescription": "<p>The Macallan Double Cask 12-Year-Old pairs the indulgent fruit, caramel, and oak spice character of Sherry-seasoned European oak with the bright citrus and vanilla notes of Sherry-seasoned American oak for a satisfyingly rich and perfectly balanced flavor experience. Awarded unanimous Double Gold upon release.</p>",
                "tastingNotes": "\"If there is royalty in the whisky world, it belongs to Scotland, and if there is a king of Scotch whisky, it's The Macallan.\" – Forbes",
                "images": [
                    "https://example.com/products/macallan-12-1.jpg"
                ],
                "sizes": [
                    {
                        "id": "sz_pqr123mn456",
                        "upc": "00812066021598",
                        "size": "750 ML",
                        "volume": "750",
                        "uom": "MILLILITRE",
                        "container": "Bottle",
                        "containerType": "Bottle",
                        "pack": false,
                        "packDesc": "",
                        "image": "https://example.com/products/macallan-12-bottle.jpg",
                        "attributes": {
                            "engraving": {
                                "status": true,
                                "maxLines": 3,
                                "maxCharsPerLine": 16,
                                "fee": 5000,
                                "location": "Below the Label"
                            }
                        }
                    }
                ]
            }
        ],
        "retailers": [
            {
                "id": "ret_abc123xyz789",
                "name": "LiquidCommerce Wine & Spirits",
                "platformFee": 499,
                "address": {
                    "one": "240 Loisaida Avenue",
                    "two": "",
                    "city": "New York",
                    "state": "NY",
                    "zip": "10009",
                    "country": "US"
                },
                "fulfillments": [
                    {
                        "id": "ful_ghi189rst123",
                        "timezone": "America/New_York",
                        "type": "onDemand",
                        "canEngrave": false,
                        "fees": {
                            "min": 1999,
                            "fee": 0,
                            "free": {
                                "active": false,
                                "min": 0
                            }
                        },
                        "expectation": {
                            "detail": "Arrives in 60 mins",
                            "short": "60 mins"
                        },
                        "hours": {
                            "monday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "10:00",
                                        "endsAt": "21:00"
                                    }
                                ]
                            },
                            "tuesday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "10:00",
                                        "endsAt": "21:00"
                                    }
                                ]
                            },
                            "wednesday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "10:00",
                                        "endsAt": "21:00"
                                    }
                                ]
                            },
                            "thursday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "10:00",
                                        "endsAt": "21:00"
                                    }
                                ]
                            },
                            "friday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "10:00",
                                        "endsAt": "21:00"
                                    }
                                ]
                            },
                            "saturday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "10:00",
                                        "endsAt": "21:00"
                                    }
                                ]
                            },
                            "sunday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "10:00",
                                        "endsAt": "21:00"
                                    }
                                ]
                            }
                        },
                        "breaks": [],
                        "items": []
                    }
                ]
            },
            {
                "id": "ret_abc123xyz189",
                "name": "LiquidCommerce Barn",
                "platformFee": 499,
                "address": {
                    "one": "1000 N 5th Ave",
                    "two": "134",
                    "city": "Vernon Hills",
                    "state": "NY",
                    "zip": "10061",
                    "country": "US"
                },
                "fulfillments": [
                    {
                        "id": "ful_abc123xyz189",
                        "timezone": "America/Chicago",
                        "type": "shipping",
                        "canEngrave": true,
                        "fees": {
                            "pack": {
                                "active": true,
                                "maxQuantity": 25,
                                "fee": 1599
                            },
                            "individual": {
                                "active": true,
                                "maxQuantity": 25,
                                "fee": 1599
                            },
                            "free": {
                                "active": false,
                                "min": 0
                            }
                        },
                        "expectation": {
                            "detail": "Ships in 2-3 days",
                            "short": "2-3 days"
                        },
                        "hours": {
                            "monday": {
                                "active": false,
                                "times": []
                            },
                            "tuesday": {
                                "active": false,
                                "times": []
                            },
                            "wednesday": {
                                "active": false,
                                "times": []
                            },
                            "thursday": {
                                "active": false,
                                "times": []
                            },
                            "friday": {
                                "active": false,
                                "times": []
                            },
                            "saturday": {
                                "active": false,
                                "times": []
                            },
                            "sunday": {
                                "active": false,
                                "times": []
                            }
                        },
                        "breaks": [],
                        "items": []
                    }
                ]
            }
        ]
    }
    curl --location 'https://staging.api.liquidcommerce.cloud/catalog/availability' \
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
    --header 'Content-Type: application/json' \
    --data '{
        "upcs": [
            "00812066021598",
            "00619947000020",
            "00081753833916",
            "00083085904081"
        ],
        "grouping": [
            "649066c19661fb45f6869934",
            "GROUPING-39553",
            "649066c19661fb45f6869937"
        ],
        "loc": {
            "address": {
                "one": "100 madison ave",
                "two": "apt 1707",
                "city": "New york",
                "state": "NY",
                "zip": "10016"
            }
        },
        "shouldShowOffHours": false,
        "isLegacy": true,
        "refresh": false,
        "isLean": false
    }'

    Unique identifier for the API request. Used for debugging and support

    path

    string

    API path

    version

    string

    API version used for the request

    giftOptions
    marketingPreferences
    deliveryTip
    deliveryInstruction
    checkoutType

    path

    string

    API path

    version

    string

    API version used for the request

    loc

    locType

    Location object for determining availability. If no address is provided there will not be availability for the requested products.

    shouldShowOffHours

    boolean

    When true, returns onDemand retailers outside their operating hours

    isLegacy

    boolean

    Whether to return legacy identifiers

    isLean

    boolean

    Whether to return a minimal response format

    refresh

    boolean

    When set to true, a new access token will be generated and returned

    navigation

    navigationSchema

    Navigation schema

    products

    array<productType>

    Array of matched products

    retailers

    array<retailerType>

    Array of available retailers

    languages

    Array<string>

    List of supported languages for the response, e.g. ["en"]

    timestamp

    string

    Unix timestamp (in milliseconds) when the response was generated

    timezone

    string

    Timezone used for the response, always "UTC"

    requestId

    string

    metaDataObject
    authObject

    Unique identifier for the API request. Used for debugging and support

    data

    Array<>

    Array of address objects

    zip

    string

    zip code

    country

    string

    country in which the address is located

    Content-Type

    application/json

    Authorization

    Bearer <YOUR_ACCESS_TOKEN>

    id

    string

    Google Places API location identifier for the selected address

    key

    string

    Your Google Places API key

    refresh

    boolean

    When set to true, a new access token will be generated and returned

    statusCode

    number

    HTTP status code of the response

    message

    string

    A brief message describing the result of the API call

    metadata

    metaDataObject

    Contains metadata about the API call

    auth

    authObject

    Authentication object, only when refresh in true

    formattedAddress

    string

    Formatted address

    coords

    coordsType

    Address coordinates

    address

    addressTypeObject

    Address info object

    one

    string

    Street address

    two

    string

    Street address

    city

    string

    City address

    state

    string

    state, you can use either 2 letter code or the full name

    Field
    Type
    Description

    languages

    Array<string>

    List of supported languages for the response, e.g. ["en"]

    timestamp

    string

    Unix timestamp (in milliseconds) when the response was generated

    timezone

    string

    Timezone used for the response, always "UTC"

    requestId

    string

    platformFee: number [optional]

    LiquidCommerce application fee per retailer

    address: [optional]

    location information split out to individual values for the street, city, state, zip code, country, latitude and longitude

    fulfillments: Array<>

    retailer available fulfillment configurations

    RetailerAddress

    Attribute
    Description

    id: string [optional]

    identifier of the address

    one: string

    retailer street address

    two: string

    retailer apt, suite, floor, etc

    city: string

    retailer city

    state: string

    retailer state, you can use either 2 letter code or the full name

    RetailerFulfillment

    Attribute
    Description

    id: string

    fulfillment identifier

    type:

    fulfillment type, ex: onDemand | shipping

    canEngrave: boolean

    indicates whether the retailer support engraving services

    deliveryFee: number [optional]

    specific delivery fee for this fulfillment

    shippingFee: number [optional]

    specific shipping fee for this fulfillment

    FeeDelivery

    Attribute
    Description

    min: number

    the minimum subtotal that must be met for the order to be placed

    fee: number

    the fee for the fulfillment service, ex: 1500

    free:

    conditions for free delivery

    FeeShipping

    Attribute
    Description

    pack:

    the shipping fee configurations for pack items

    individual:

    the shipping fee configurations for individual items

    free:

    conditions for free delivery

    FeeShippingConfig

    Attribute
    Description

    fee: number

    The fee for the fulfillment service, ex: 1500

    active: boolean

    The status of of the fulfillment shipping method

    min: number

    The min item total required to checkout

    maxQuantity: number

    The maximum number of products allowed

    FreeDelivery

    Attribute
    Description

    active: boolean

    whether free delivery is available

    min: number

    minimum purchase amount for free delivery

    Expectation

    Attribute
    Description

    detail: string

    detailed expectation of fulfillment, ex: Ships in 3 days

    short: string

    short expectation of fulfillment, ex: 3 days

    engraving: string

    detailed expectation of engravable shipping fulfillment, ex: Ships in 10 days

    Note: engraving attribute will be returned only for shipping fulfillments and not onDemand.

    Hours

    Attribute
    Description

    [DayOfWeek]:

    hours of operations for each day of the week, ex:

    DayConfigs

    Attribute
    Description

    active: boolean

    whether the day is available for scheduling

    times: Array<>

    the times available for scheduling, ex:

    Time

    Attribute
    Description

    startsAt: string

    the expected start time for the day, ex: 08:30

    endsAt: string

    the expected end time for the day, ex: 23:00

    Sample retailer

    Retailer Object

    id: string

    retailer identifier

    name: string

    retailers name, ex: Liquid Wine and Spirits

    Session

    Get new session for payments management

    Endpoint Details

    POST /users/session

    curl --location 'https://staging.api.liquidcommerce.cloud/address/details' \
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
    --header 'Content-Type: application/json' \
    --data '{
      "id": "placeid_123abc456ef",
      "key": "<YOUR_GOOGLE_PLACES_API_KEY>"
    }'
    {
        "statusCode": 200,
        "message": "Get the longitude and latitude of the address you requested",
        "metadata": {
            "languages": [
                "en"
            ],
            "timestamp": 1731594349056,
            "timezone": "UTC",
            "requestId": "reqid_123abc45def",
            "path": "/api/address/details",
            "version": "1.7.0"
        },
        "data": {
            "formattedAddress": "100 Madison Avenue, Lakewood, NJ 08701",
            "coords": {
                "lat": 40.091142,
                "long": -74.2169165
            },
             "address": {
                    "one": "100 Madison Avenue",
                    "two": "",
                    "city": "Lakewood",
                    "state": "NJ",
                    "zip": "08701",
                    "country": "US",
                }
    ```
        }
    }
    [
        {
                "id": "retailerId_123abc123abc",
                "name": "Cheers On Demand",
                "platformFee": 499,
                "address": {
                    "one": "867 Fillmore St",
                    "two": "",
                    "city": "San Francisco",
                    "state": "CA",
                    "zip": "94117",
                    "country": "US"
                },
                "fulfillments": [
                    {
                        "id": "6570c3ec700628ce1910c155",
                        "timezone": "America/Los_Angeles",
                        "type": "onDemand",
                        "canEngrave": false,
                        "doesAllowPromos": false,
                        "doesAllowGiftCards": false,
                        "productTypesAllowed": [],
                        "fees": {
                            "min": 2500,
                            "fee": 0,
                            "free": {
                                "active": false,
                                "min": 2500
                            }
                        },
                        "expectation": {
                            "detail": "Arrives in 60 mins",
                            "short": "60 mins"
                        },
                        "hours": {
                            "monday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "08:00",
                                        "endsAt": "23:30"
                                    }
                                ]
                            },
                            "tuesday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "08:00",
                                        "endsAt": "23:30"
                                    }
                                ]
                            },
                            "wednesday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "08:00",
                                        "endsAt": "23:30"
                                    }
                                ]
                            },
                            "thursday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "08:00",
                                        "endsAt": "23:30"
                                    }
                                ]
                            },
                            "friday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "08:00",
                                        "endsAt": "23:30"
                                    }
                                ]
                            },
                            "saturday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "08:00",
                                        "endsAt": "23:59"
                                    }
                                ]
                            },
                            "sunday": {
                                "active": true,
                                "times": [
                                    {
                                        "startsAt": "08:00",
                                        "endsAt": "23:59"
                                    }
                                ]
                            }
                        },
                        "breaks": [],
                        "items": []
                    }
                ]
            }
    ]

    Unique identifier for the API request. Used for debugging and support

    path

    string

    API path

    version

    string

    API version used for the request

    addressObject

    zip: string

    retailer zip code

    country: string

    retailer country where the address is located

    lat: number

    retailer latitude, ex: 40.744860

    long: number

    retailer longitude, ex: -73.985314

    engravingFee: number [optional]

    specific engraving fee for this fulfillment

    platformFee: number [optional]

    platform fee for this fulfillment

    subtotal: number [optional]

    Subtotal for items in this fulfillment

    timezone: string [optiona]

    timezone associated with the fulfillment

    fees: FeeShipping | FeeDelivery

    fulfillment's fee configurations, if the fulfillment type is shipping(FeeShipping), if the fulfillment type is onDemand(FeeDelivery)

    expectation: Expectation

    fulfillment's expectation configurations

    hours: Hours

    fulfillment's hours configurations

    breaks: Array<Time>

    the breaks within the working hours

    items: Array<string>

    fulfillment's item ids

    doesAllowPromos: boolean

    indicates whether the retailer per fulfillment level support promo codes for cart & checkout

    doesAllowGiftCards: boolean

    indicates whether the retailer per fulfillment level support gift cards for checkout

    productTypesAllowed: Array<string>

    list of fulfillment categories allowed

    RetailerAddress
    RetailerF
    ulfillment
    Modalities
    FreeDelivery
    FeeShippingConfig
    FeeShippingConfig
    FreeDelivery
    DayConfig
    Time
    enum DAY_OF_WEEK {
      MONDAY = 'monday',
      TUESDAY = 'tuesday',
      WEDNESDAY = 'wednesday',
      THURSDAY = 'thursday',
      FRIDAY = 'friday',
      SATURDAY = 'saturday',
      SUNDAY = 'sunday'
    }
    "monday": {
      "active": true,
      "times": [ 
        {
          "startsAt": "00:00", 
          "endsAt": "23:59"
        } 
      ]
    }
    "times": [ 
      {
        "startsAt": "00:00", 
        "endsAt": "23:59"
      } 
    ]
    Headers
    Header
    Value

    Content-Type

    application/json

    Authorization

    Bearer <YOUR_ACCESS_TOKEN>

    Body

    Parameter
    Type
    Description
    Required

    email

    string

    User's email address

    firstName

    string

    User's first name

    lastName

    string

    User's last name

    Response Details

    Field
    Type
    Description

    statusCode

    number

    HTTP status code of the response

    message

    string

    A brief message describing the result of the API call

    metadata

    Contains metadata about the API call

    auth

    Authentication object

    Metadata Object

    User Session

    Field
    Type
    Description

    id

    string

    User's identifier

    email

    string

    User's email address

    firstName

    string

    User's first name

    lastName

    Session

    Attribute
    Description

    key: string

    session key

    secret: string

    session secret

    createdAt: Date

    session creation timestamp

    Sample Request and Response

    Field
    Type
    Description
    {
        "statusCode": 201,
        "message": "Creating a new session succeeded",
        "metadata": {
            "languages": [
                "en"
            ],
            "timestamp": 1731595854533,
            "timezone": "UTC",
            "requestId": "reqid_123abc45def",
            "path": "/api/users/session",
            "version": "1.7.0"
        },
        "data": {
            "id": "usrid_123abc456def",
            "email": "[email protected]",
            "firstName": "John",
            "company": "",
            "lastName": "Smith",
            "phone": null,
            "profileImage": "",
            "birthDate": null,
            "createdAt": "2024-11-14T13:17:47.482Z",
            "updatedAt": "2024-11-14T14:50:54.613Z",
            "addresses": [],
            "savedPayments": [],
            "session": {
                "key": "SESSION_KEY",
                "secret": "SECRET_KEY",
                "createdAt": "2024-11-14T14:50:54.843Z"
            }
        }
    }
    curl --location 'https://staging.api.liquidcommerce.cloud/users/session' \
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
    --header 'Content-Type: application/json' \
    --data '{
        "email": "[email protected]",
        "firstName": "John",
        "lastName": "Smith"
    }'

    path

    string

    API path

    version

    string

    API version used for the request

    company

    string

    User's company name

    phone

    string

    User's phone number in E.164 format

    profileImage

    string

    URL of user's profile image

    birthDate

    string

    User's birth date in YYYY-MM-DD format

    id

    string

    Existing user identifier (for updates only), email becomes optional

    data

    userSession

    User session

    string

    User's last name

    phone

    string

    User's phone number

    company

    string

    User's company

    profileImage

    string

    URL to user's profile image

    birthDate

    string

    Users's birth date

    createdAt

    date

    Account creation timestamp

    updatedAt

    date

    Last update timestamp

    addresses

    Array<UserAddress>

    User's saved addresses

    savedPayments

    Array<UserPayment>

    User's saved payment methods

    session

    Session

    User's current session information

    languages

    Array<string>

    List of supported languages for the response, e.g. ["en"]

    timestamp

    string

    Unix timestamp (in milliseconds) when the response was generated

    timezone

    string

    Timezone used for the response, always "UTC"

    requestId

    string

    metaDataObject
    authObject

    Unique identifier for the API request. Used for debugging and support

    Methods & Usage

    Usage

    The SDK requires configuration during initialization:

    Before initializing the SDK clients, you'll need a Google Places API Key from your Google Cloud Console. This key is required for location-based features and should be kept secure.

    LiquidCommerce Client

    LiquidCommerceOrders Client

    Response Types

    All API responses follow a consistent structure:

    Methods

    Address

    While the SDK handles authentication automatically, you can also manually retrieve the authentication details:

    Address

    Services for address validation and lookup:

    Catalog

    Product catalog search and availability services:

    Cart

    Shopping cart management:

    User

    User profile and preferences management:

    Payment Element

    The Payment Element is a secure and modern UI component for collecting payment details. It simplifies PCI compliance by handling all sensitive information within an iframe.

    Prerequisites

    Before mounting the Payment Element, you must create a payment session. This can be tied to a user, cart, or checkout.

    Integration

    1

    Initialize and Mount

    The LiquidCommercePaymentElement function creates and manages the UI component.

    2

    Generate a Confirmation Token

    Once the user has filled out the payment form, create a confirmation token. This token securely represents the payment details.

    3

    Legacy Payment

    Use the new integration that has the UI and API methods decoupled, allowing you to use the SDK entirely server side.

    The payment system uses secure elements for handling sensitive payment data. Before using payment features, you must first create a user session.

    Prerequisites

    1. User Session Creation:

    Payment Element Integration

    Security Considerations

    1. PCI Compliance: The payment element handles card data securely within an iframe, ensuring your application never directly touches sensitive payment information.

    2. Token-Based: All payment data is tokenized - you only receive secure tokens that can't be used to retrieve the original card details.

    3. Single Use: Payment tokens are single-use and expire after a short time period.

    4. Domain Validation: Payment elements will only work on domains that have been pre-registered with your account.

    Best Practices

    1. Error Handling: Always implement proper error handling:

    1. Cleanup: Always clean up payment elements when done:

    • When navigation away from payment page

    • After successful payment

    • After failed payment attempt

    • Before unmounting payment component

    1. Event Handling: Monitor element state for better user experience:

    Responsive Design

    The payment element automatically adapts to:

    • Mobile and desktop viewports

    • Right-to-left languages

    • Dark/light themes

    • Different container sizes

    Testing Cards

    When testing payments in staging environment, use these test cards:

    These cards will be accepted in test mode and will simulate successful payments. They should only be used in the staging environment, never in production.

    Important Notes:

    • These cards work only in test/staging environment

    • Real cards will be declined in test mode

    • Test cards will be declined in production

    • All test transactions use simulated funds

    Testing Environment Limitations ⚠️ Important Testing Note When doing and checkout complete on the testing environment, certain transaction amount ranges may be intentionally restricted to simulate payment declines, gateway errors, or other failures. This allows you to verify that your integration can handle error scenarios correctly.

    Example — Amounts that may trigger simulated errors:

    • $2000.00 – $2999.99: Processor Declined

    • $3000.00 – $3000.99: Processor Network Unavailable

    • $5001.00: Gateway Rejected (Application Incomplete)

    For routine testing, avoid using these ranges unless you specifically want to test error-handling behavior.

    Checkout

    Checkout process management:

    Checkout Payment

    For direct checkout payments, the flow is similar but uses the checkout session:

    Orders

    Provides secure access to order data throughout the finalized states of the order lifecycle within the LiquidCommerce ecosystem.

    Fetch by ID

    Webhook Test

    Error Handling

    The SDK throws errors for various scenarios. Always wrap SDK calls in try-catch blocks:

    Common error scenarios:

    • Authentication failures

    • Invalid parameters

    • Network errors

    • Resource not found

    Price Handling

    All monetary values in the SDK are handled in cents (the smallest currency unit). For example:

    • $10.00 is represented as 1000

    • $5.99 is represented as 599

    • $0.50 is represented as 50

    import LiquidCommerce from '@liquidcommerce/cloud-sdk';
    
    // Your Account token provided to you through 
    // your account representative
    const client = await LiquidCommerce('YOUR_LIQUIDCOMMERCE_API_KEY', {
      googlePlacesApiKey: 'YOUR_GOOGLE_PLACES_API_KEY',
      env: 'stage' // or 'prod'
    });
    
    // Initialize the client
    await client.init();
    import LiquidCommerceOrders from '@liquidcommerce/cloud-sdk';
    
    // Your Account user and passoword will be provided to you 
    // through your account representative
    const orderClient = await LiquidCommerceOrders({
      userID: 'YOUR_ORDER_API_USER_ID',
      password: 'YOUR_ORDER_API_PASSWORD',
      env: LIQUID_COMMERCE_ENV.STAGE, // or PROD
    });
    
    // Initialize the client
    await orderClient.init();

    Confirm the Payment Session

    Use the confirmation token to finalize the payment and retrieve the payment method details.

    4

    Lifecycle Management

    Properly manage the element's lifecycle to ensure a smooth user experience and resource cleanup.

    Rate limiting
  • Validation errors

  • Payment Element
    const confirmation = await client.user.confirmPaymentSession(confirmationToken);
    
    if (confirmation.data) {
      const paymentMethod = confirmation.data;
      // Now you have the payment method ID, card details, etc.
      // e.g., paymentMethod.id, paymentMethod.card.brand
    }
    // Listen to events
    paymentElement.subscribe('ready', () => {
      console.log('Payment element is ready.');
    });
    
    paymentElement.subscribe('change', (event) => {
      // Handle form state changes (e.g., enable/disable submit button)
    });
    
    // Clean up when the element is no longer needed
    paymentElement.unmount();
    paymentElement.destroy();
    interface ApiResponse<T> {
      statusCode: number;
      message: string;
      metadata: {
        languages: string[];
        timestamp: number;
        timezone: string;
        requestId: string;
        path: string;
        version: string;
      };
      data?: T; // Present in responses with data
    }
    // Manually retrieve authentication details
    try {
      const authDetails = await client.auth();
      console.log('Access Token:', authDetails.token);
      console.log('Expires In:', authDetails.exp);
    } catch (error) {
      console.error('Failed to get auth details:', error);
    }
    // Address autocompletion
    const autocompleteResponse = await client.address.autocomplete({
      input: '100 Madison Ave, New York'
    });
    
    // Response type: IApiResponseWithData<IAddressAutocompleteResult[]>
    // {
    //   id: string;
    //   description: string;
    // }
    
    // Get detailed address information
    const detailsResponse = await client.address.details({
      id: 'ChIJd8BlQ2BZwokRjMKtTjMezRw'
    });
    
    // Response type: IApiResponseWithData<IAddressDetailsResult>
    // {
    //   formattedAddress: string;
    //   coords: {
    //     lat: number;
    //     long: number;
    //   }
    //   address: {
    //     one: string,
    //     two: string,
    //     city": string,
    //     state: string,
    //     zip: string,
    //     country: "US"
    //   }
    // }
    // Check product availability
    const availabilityResponse = await client.catalog.availability({
      upcs: ['123456789012', '210987654321'], // UPC codes
      grouping: ['group1', 'group2'], // Optional group identifiers
      ids: ['id1', 'id2'], // Optional product IDs
      loc: {
        address: {
          one: '123 Main St',
          city: 'New York',
          state: 'NY',
          zip: '10001'
        }
      },
      shouldShowOffHours: true
    });
    
    // Search catalog with filters
    const searchResponse = await client.catalog.search({
      search: 'whiskey',
      pageToken: "",
      entity: "",
      page: 1,
      perPage: 20,
      orderBy: ENUM_ORDER_BY.PRICE,
      orderDirection: ENUM_NAVIGATION_ORDER_DIRECTION_TYPE.ASC,
      filters: [
        { 
          key: ENUM_FILTER_KEYS.CATEGORIES, 
          values: [ENUM_SPIRITS.WHISKEY] 
        },
        { 
          key: ENUM_FILTER_KEYS.PRICE, 
          values: { min: 2000, max: 10000 } // Prices in cents
        },
        {
          key: ENUM_FILTER_KEYS.AVAILABILITY,
          values: ENUM_AVAILABILITY_VALUE.IN_STOCK
        }
      ],
      loc: {
        address: {
          one: '123 Main St',
          city: 'New York',
          state: 'NY',
          zip: '10001'
        }
      }
    });
    // Create new cart
    const newCart = await client.cart.get();
    
    // Retrieve existing cart
    const existingCart = await client.cart.get('cart_id', true); // Second parameter for refresh
    
    // Update cart
    const updatedCart = await client.cart.update({
      id: 'cart_id',
      items: [
        {
          partNumber: '123456789012_retailer_id', // Required: {UPC}_{retailerId}
          quantity: 2,
          fulfillmentId: 'fulfillment_id',
          engravingLines: ['Line 1', 'Line 2'], // Optional
          scheduledFor: '2024-12-25', // Optional
        }
      ],
      loc: {
        address: {
          one: '123 Main St',
          city: 'New York',
          state: 'NY',
          zip: '10001'
        }
      },
      promoCode: 'DISCOUNT10', // Optional
      giftCards: ['GC123456'] // Optional
    });
    // Create/update user session
    const userSession = await client.user.session({
      email: "[email protected]",
      firstName: "John",
      lastName: "Smith",
      phone: "2125551234",
      company: "Company Inc",
      profileImage: "https://...",
      birthDate: "1990-01-01",
      id:'user_id', // Existing user identifier (for updates only), email becomes optional
    });
    
    // Fetch user by ID or email
    const userData = await client.user.fetch('user_id_or_email');
    
    // Address management
    const newAddress = await client.user.addAddress({
      customerId: 'customer_id',
      placesId: 'google_places_id', // Optional if providing address details
      one: '100 Madison St',
      two: 'Apt 4B',
      city: 'New York',
      state: 'NY',
      zip: '10004',
      country: 'US',
      lat: 40.7128, // Optional
      long: -74.0060, // Optional
      type: ENUM_ADDRESS_TYPE.SHIPPING,
      isDefault: true
    });
    
    const updatedAddress = await client.user.updateAddress({
      // Same parameters as addAddress
    });
    
    // Payment methods
    
    // 1. First create/retrieve a user session
    const userSession = await client.user.session({
      email: "[email protected]",
      // ... other user details
    });
    
    // 2. Initialize payment form with session data
    // The session response includes payment configuration in the auth object
    await client.payment.mount({
      clientSecret: userSession.data.session.setupIntent, // From user session response
      key: userSession.data.session.publicKey,           // From user session response
      elementId: 'payment-element-container',
      appearance: { 
        theme: 'night' // 'default' | 'night' | 'flat'
      },
      elementOptions: { 
        layout: 'tabs' // 'tabs' | 'accordion' | 'auto'
      }
    });
    
    // 3. Listen for payment element events
    client.payment.subscribe('ready', () => {
      console.log('Payment element is ready');
    });
    
    client.payment.subscribe('change', (event) => {
      // Handle validation and form state changes
      console.log('Payment element changed:', event);
    });
    
    // 4. When user submits, generate payment token
    const tokenResult = await client.payment.generateToken();
    if ('error' in tokenResult) {
      console.error('Token generation failed:', tokenResult.error);
      // Handle error cases:
      // - validation_error: Invalid payment details
      // - api_error: Server/API issues
      // - client_error: SDK/setup issues
      // - confirm_error: Payment confirmation failed
    } else {
      // Payment method successfully created
      console.log('Payment token:', tokenResult.id);
      
      // 5. Add payment method to user profile
      await client.user.addPayment({
        userId: userSession.data.id,
        paymentMethodId: tokenResult.id,
        isDefault: true
      });
    }
    
    // 6. Clean up
    client.payment.unmount();
    client.payment.destroy();
    
    // Data removal
    await client.user.purge('user_id_or_email');
    await client.user.purgeAddress('address_id');
    await client.user.purgePayment('user_id', 'payment_id');
    // Create a payment session to get a client secret
    const paymentSession = await client.user.paymentSession({
      // Optionally link to a cart, checkout, or customer
      // cartId: 'your_cart_id',
      // checkoutToken: 'your_checkout_token',
      // customerId: 'your_customer_id',
    });
    
    const { key, secret } = paymentSession.data.session;
    // Initialize the payment element
    const paymentElement = LiquidCommercePaymentElement({
      session: {
        key, // Public key from payment session
        secret, // Client secret from payment session
      },
    });
    
    // Mount the element to a container in your DOM
    await paymentElement.mount({
      elementId: 'payment-element-container',
      appearance: {
        theme: 'night', // 'stripe' | 'night' | 'flat'
      },
      elementOptions: {
        layout: 'tabs', // 'tabs' | 'accordion' | 'auto'
      },
    });
    const result = await paymentElement.createConfirmationToken();
    
    if (result.token) {
      // Token successfully created
      const confirmationToken = result.token;
      // Use this token to complete the checkout or save the payment method
    } else {
      // Handle error
      console.error(result.message);
    }
    // First create or get a user session
    const userSession = await client.user.session({
      email: "[email protected]",
      // ... other user details
    });
    
    // The session response includes necessary payment credentials
    const { secret, key } = userSession.data.session;
    // Initialize payment form using session credentials
    await client.payment.mount({
      clientSecret: secret,  // Required: From user session response
      key,                   // Required: From user session response
      elementId: 'payment-element-container',             // Your DOM element ID
      appearance: { 
        theme: 'night'  // 'default' | 'night' | 'flat'
      },
      elementOptions: { 
        layout: 'tabs'  // 'tabs' | 'accordion' | 'auto'
      }
    });
    
    // Monitor payment element state
    client.payment.subscribe('ready', () => {
      // Element is ready to accept input
    });
    
    client.payment.subscribe('change', (event) => {
      const { complete, empty, value } = event;
      // Handle validation state changes
    });
    
    // Process payment when ready
    const tokenResult = await client.payment.generateToken();
    
    // Handle the result
    if ('error' in tokenResult) {
      const { type, message, code } = tokenResult.error;
      // type can be: 'validation_error' | 'api_error' | 'client_error' | 'confirm_error'
    } else {
      // Use tokenResult.id for checkout completion or saving payment method
      const { id, card } = tokenResult;
    }
    
    // Always clean up when done
    client.payment.unmount();
    client.payment.destroy();
    try {
      const token = await client.payment.generateToken();
      if ('error' in token) {
        switch(token.error.type) {
          case 'validation_error':
            // Handle invalid card data
            break;
          case 'api_error':
            // Handle API/network issues
            break;
          case 'client_error':
            // Handle setup/configuration issues
            break;
          case 'confirm_error':
            // Handle payment confirmation failures
            break;
        }
      }
    } catch (error) {
      // Handle unexpected errors
    }
    client.payment.subscribe('change', (event) => {
      // Update UI based on validation state
      const { complete, empty } = event;
      submitButton.disabled = !complete || empty;
    });
    
    client.payment.subscribe('loaderror', (event) => {
      // Handle element loading failures
      console.error('Payment element failed:', event.error);
    });
    // Test Visa Card
    Card Number: 4242 4242 4242 4242
    Expiry: Any future date
    CVC: Any 3 digits
    ZIP: Any 5 digits
    
    // Test Mastercard
    Card Number: 5555 5555 5555 4444
    Expiry: Any future date
    CVC: Any 3 digits
    ZIP: Any 5 digits
    
    // Example test card usage:
    /*
      Card: 4242 4242 4242 4242
      Expiry: 12/29
      CVC: 123
      ZIP: 10001
    */
    // Prepare checkout
    const preparedCheckout = await client.checkout.prepare({
      cartId: "cart_id",
      customer: {
        id: "customer_id", // Optional
        email: "[email protected]", // Required
        firstName: "John",
        lastName: "Smith",
        phone: "2125551234",
        birthDate: "1990-01-01"
      },
      hasAgeVerify: true,
      billingAddress: {
        firstName: "John",
        lastName: "Smith",
        email: "[email protected]",
        phone: "2125551234",
        one: "123 Main St",
        two: "Apt 4B",
        city: "New York",
        state: "NY",
        zip: "10001",
        country: "US"
      },
      hasSubstitutionPolicy: true,
      isGift: true,
      billingSameAsShipping: false,
      giftOptions: {
        message: "Happy Birthday!",
        recipient: {
          name: "Jane Smith",
          email: "[email protected]",
          phone: "2125555678"
        }
      },
      marketingPreferences: {
        canEmail: true,
        canSms: true
      },
      deliveryTips: [
        {
          fulfillmentId: "fulfillment_id",
          tip: 500 // Amount in cents
        }
      ],
      deliveryInstructions: [
        {
          fulfillmentId: 'fulfillment_id',
          instructions: "", // 250 Max characters
        },
      ],
      acceptedAccountCreation: true,
      scheduledDelivery: "2024-12-25T14:00:00Z",
      promoCode: 'DISCOUNT10', // Optional
      giftCards: ['GC123456'], // Optional
    });
    
    // Complete checkout
    const completedCheckout = await client.checkout.complete({
      token: preparedCheckout.token,
      payment: "payment_id"
    });
    // 1. First prepare the checkout
    const preparedCheckout = await client.checkout.prepare({
      cartId: 'cart_id',
      // ... other checkout details
    });
    
    // 2. Initialize payment element with checkout session
    const paymentElement = LiquidCommercePaymentElement({
      session: {
        key: preparedCheckout.data.payment.publicKey, // From checkout prepare response
        secret: preparedCheckout.data.payment.clientSecret, // From checkout prepare response
      }
    });
    
    // 3. Mount the element
    await paymentElement.mount({
      elementId: 'payment-element-container',
      appearance: { theme: 'night' },
      elementOptions: { layout: 'tabs' },
    });
    
    // 4. Handle payment element events and create confirmation token
    const result = await paymentElement.createConfirmationToken();
    
    if (result.token) {
      // 5. Confirm the payment collected with the confirmation token
      const confirmation = await client.user.confirmPaymentSession(confirmationToken);
     
     if (confirmation?.data?.id) {
        // 6. Complete checkout with the confirmation token
        const completedCheckout = await client.checkout.complete({
          token: preparedCheckout.data.token,
          payment: confirmation?.data?.id,
        });
      }
    }
    
    // 7. Clean up
    paymentElement.unmount();
    paymentElement.destroy();
    const orderClient = await LiquidCommerceOrders({
      userID: 'YOUR_ORDER_API_USER_ID',
      password: 'YOUR_ORDER_API_PASSWORD',
      env: LIQUID_COMMERCE_ENV.STAGE, // or PROD
    });
    
    // Fetch order details by ID or number
    const orderResponse = await orderClient.order.fetch(/* reference id or order number */);
    // Test webhook endpoint
    const webhookTestResult = await client.webhook.test(/* endpoint */);
    
    // Response is a simple boolean indicating success or failure
    // true = webhook test was successful
    // false = webhook test failed
    try {
      const result = await client.someMethod();
    } catch (error) {
      console.error('Operation failed:', error.message);
      // Handle specific error cases
    }

    Product

    A full reference to a product type for different Liquid Commerce APIs.

    ProductType

    Attribute
    Description

    id: string

    identifier of the product

    name: string

    Size

    Attribute
    Description

    ProductSizeAttributes

    Attribute
    Description

    ProductPresale

    Attribute
    Description

    Attributes

    Attribute
    Description

    ProductSizeEngraving

    Attribute
    Description

    Variants

    Attribute
    Description

    VariantFulfillmentTypes

    Attribute
    Description

    AttributesImage

    Attribute
    Description

    AttributesAward

    Attribute
    Description

    AttributesRecipe

    Attribute
    Description

    AttributesRecipeIngredient

    Attribute
    Description

    AttributesVideo

    Attribute
    Description

    AttributesTastingNote

    Attribute
    Description

    AttributesPersonalization

    Attribute
    Description

    ProductPriceInfo

    Attribute
    Description

    Sample product

    Product Object

    Search

    Provides access to intelligent search and filtering across your catalog

    Endpoint Details

    POST /catalog/search

    Headers

    Header
    Value

    Body

    Parameter
    Type
    Description
    Required

    Response Details

    Field
    Type
    Description

    Metadata Object

    Sample Request and Response

    each size's container type, ex: Glass

    pack: boolean

    whether the size is a pack, ex: true

    packDesc: string

    if the size is a pack and a description is available, ex: 8pk

    volume: string

    volume measurement

    uom: string

    unit of measure

    image: string

    product size specific image (if available, otherwise defaults to the mainImage)

    attributes:

    each size's attributes

    modalities: [optional]

    available fulfillment modalities

    variants: Array<>

    each retailer's available variant for the size

    product awards

    recipes: Array<>

    related recipes

    video: Array<>

    product videos

    tastingNotes: Array<>

    detailed tasting notes

    personalizations: Array<>

    personalization options

    engraving location on the product, ex: Above the label

    variant sale price, ex: 1199 ($11.99)

    stock: number

    variant stock quantity, ex: 82

    fulfillmentTypes:

    variants retailer offered fulfillment based on type

    fulfillments: string[]

    fulfillment identifier (used to map the Array<>),

    ex: ["6570c3ec700628ce1910c265", "6565f4e8700628ce19106b14"]

    height for personalization area

    image: string

    personalization reference image url

    fee: number

    cost of personalization

    availableFrom: Date

    start date for personalization availability

    availableTo: Date

    end date for personalization availability

    product name

    salsifyGrouping: string [optional]

    optional Salsify grouping identifier

    brand: string

    product brand

    catPath: string

    the category path normalized through our liquid taxonomy

    category: string

    normalized category

    classification: string

    product classification, ex: Canadian Whiskey

    type: string

    product type, ex: Whiskey

    subType: string

    product type, ex: Flavored Whiskey

    region: string

    product region, ex: Toronto

    country: string

    country of origin, ex: Canada

    material: string

    material used in production, ex: Grains

    color: string

    product color, ex: Tawny/Brown

    flavor: string

    product flavor profile, ex: Apple

    variety: string

    product variety, ex: Blend-Grains

    appellation: string

    similar to country or region, ex: Canada

    abv: string

    product alcohol by volume, ex: 40 (40%)

    proof: string

    alcohol proof

    age: string

    product age, ex: 14

    vintage: string

    year of production/harvest, ex: 2020

    description: string

    a product detailed description, max length: 250 characters

    htmlDescription: string

    a product detailed description with html tags, max length: 250 characters

    tastingNotes: string

    product tasting notes breakdown, max length: 250 characters

    additionalInformation: string [optional]

    a product additional information

    images: string[] | Array<Record<string, any>>

    product images

    sizes: Array<Size>

    all of the available sizes for the product

    attributes: Partial<Attributes> [optional]

    optional product attributes

    priceInfo: ProductPriceInfo | null

    represents product price information

    id: string

    identifier of the product size

    size: string

    product size, ex: 750ML

    salsifyPid: string [optional]

    optional Salsify product identifier

    upc: string

    each size's UPC

    container: string

    each size's container, ex: Bottle

    engraving: ProductSizeEngraving

    Each size's engraving attributes

    presale: ProductPresale

    Representing a product presale

    maxQuantityPerOrder: number [optional]

    Maximum quantity per order allowed for this product

    canPurchaseOn: Date | null

    The date when the product can be added to the cart

    estimatedShipBy: Date | null

    The date when the product is expected to ship

    isActive: boolean

    Indicates whether the presale is currently active

    language: string

    The language associated with the product presale

    brandOrigin: string

    brand's origin information

    originStatement: string

    detailed origin description

    ownershipType: Array<string>

    types of ownership

    tags: Array<string>

    product tags

    images: AttributesImage

    product image configurations

    status: boolean

    whether engraving is activated if true

    validated: boolean [optional]

    engraving validation

    maxLines: number

    the maximum number of line allowed, ex: the maximum allowed in this example id 2 (maxLines: 2) [ "Happy Birthday", "100 more!" ]

    maxCharsPerLine: number

    the maximum number of characters allowed per line, ex: 14 it includes whitespaces

    fee: number

    engraving price, ex: 5000 ($50.00)

    partNumber: string

    variant identifier (used to add to cart), ex: 00082002599562_6565f4e5ddec8ce19105d26

    retailerId: string

    retailer identifier (used to map the Array<Retailer>), ex: 6565f4e8700628ce19106b14

    price: number

    variant price, ex: 1499

    isEngravable: boolean

    whether this retailer's variant allows engraving, ex: true

    modalities: string[]

    the methods of fulfillment available for the variant, ex: [ 'shipping', 'onDemand' ]

    shipping: string

    retailer's shipping fulfillment Id, * ONLY SHIPPING RETAILERS CAN HANDLE ENGRAVING ORDER *

    onDemand: string

    retailer's onDemand fulfillment Id

    backOfBottle: string

    url for back of bottle image

    frontOfBottle: string

    url for front of bottle image

    lifestyle: Array<string>

    array of lifestyle image urls

    image: string

    award image url

    statement: string

    award statement text

    title: string

    award title

    image: string

    recipe image url

    ingredients: Array<AttributesRecipeIngredient>

    array of recipe ingredients

    steps: Array<string>

    array of recipe steps

    title: string

    recipe title

    name: string

    ingredient name

    amount: string

    amount needed for recipe

    link: string

    video url

    image: string

    video thumbnail image url

    title: string

    video title

    statement: string

    tasting note description

    image: string

    associated image url

    title: string

    tasting note title

    type: string

    type of personalization

    engravingMaxLines: number

    maximum number of lines for engraving

    engravingMaxCharsPerLine: number

    maximum characters per line for engraving

    location: Array<string>

    available locations for personalization

    width: number

    width for personalization area

    currency: string

    the currency code for the prices

    minimum: number

    the lowest price available for this product across all retailers

    average: number

    the average price of the product across all retailers

    maximum: number

    the highest price available for this product across all retailers

    containerType: string

    awards: Array<>

    location: string

    salePrice: number

    height: number

    page

    integer

    Page number for pagination (starts at 0)

    perPage

    integer

    Number of results to return per page

    visitorId

    string

    Unique identifier for the visitor/user to enable personalized results

    retailers

    array<string>

    Array of retailer identifiers

    orderBy

    string

    Field to sort results by. Possible values: "price", "name", "brand", "price")

    orderDirection

    string

    Sort direction. Possible values: "asc", "desc"

    filters

    array<>

    Array of filter objects to refine search results

    loc

    Location object for determining real-time availability

    isLegacy

    boolean

    Whether to return legacy identifiers

    isLean

    boolean

    Whether to return a minimal response format

    refresh

    boolean

    When set to true, a new access token will be generated and returned

    navigation

    Navigation schema

    products

    array<>

    Array of matched products

    retailers

    array<>

    Array of available retailers

    Content-Type

    application/json

    Authorization

    Bearer <YOUR_ACCESS_TOKEN>

    search

    string

    Text to search for in the catalog. Can include product names, brands, or other attributes

    pageToken

    string

    Token for pagination, used to retrieve the next or previous page of results

    entity

    string

    Entity identifier for personalized results

    statusCode

    number

    HTTP status code of the response

    message

    string

    A brief message describing the result of the API call

    metadata

    metaDataObject

    Contains metadata about the API call

    auth

    authObject

    Authentication object, only when refresh in true

    Field
    Type
    Description

    languages

    Array<string>

    List of supported languages for the response, e.g. ["en"]

    timestamp

    string

    Unix timestamp (in milliseconds) when the response was generated

    timezone

    string

    Timezone used for the response, always "UTC"

    requestId

    string

    {
      "id": "50726f643247373737343330",
      "name": "TITO'S HANDMADE VODKA",
      "salsifyGrouping": "GROUPING-33277",
      "brand": "TITO'S",
      "catPath": "Spirits > Vodka > Regular Vodka",
      "category": "Spirits",
      "classification": "Vodka",
      "type": "Regular Vodka",
      "subType": "",
      "region": "TEXAS",
      "country": "UNITED STATES",
      "material": "GRAIN",
      "color": "WHITE",
      "flavor": "",
      "variety": "CORN",
      "appellation": "TEXAS",
      "vintage": "",
      "description": "Tito's Handmade Vodka is America's Original Craft Vodka produced in Austin, Texas. Tito's is known for its high-quality product, charitable giving, and goal to make people happy while making the world a better place. Tito's is crafted in old-fashioned pot stills, with each batch taste-tested. Exceptionally smooth with an impeccably clean finish, our unflavored, low-calorie vodka is six times distilled, made from corn, and naturally gluten-free with no carbs or sugar*. From a Bloody Mary at brunch, a Transfusion on the golf course, or a simple Tito's and soda with friends, make every occasion a celebration with Tito's! Tito's Handmade Vodka turns spirits into love and goodness with Love, Tito's, the philanthropic heart of the company, supporting thousands of nonprofit organizations across the U.S. — and around the world — amplifying their missions of disaster relief and response, community building, animal welfare, veteran services, and so much more. Available in Liter, 1.75L, 750mL, 375mL, 200mL, and 50mL sizes. For more information, visit titosvodka.com.\n\n*(Average Analysis per 1.5 oz Tito's Handmade Vodka: 98 calories, Carbohydrates 0 grams, Protein 0 grams, Fat 0 grams, Sugar 0 grams)\n\nMADE IN BATCHES: Tito's Handmade Vodka is made in Austin, Texas, and distilled in old-fashioned pot stills, with each batch taste-tested.\n\nMADE FROM CORN: Our unflavored vodka is distilled from corn, making it naturally gluten-free. Tito's is 98 calories per 1.5 oz serving, and 65 calories per 1 oz serving.\n\nMIXES WITH EVERYTHING: Tito's mixes with everything, from a classic Tito's Soda Lime to the iconic Bloody Mary to a refreshing Tito's Transfusion, the official drink of the green.\n\nSPREAD THE LOVE: Tito's Handmade Vodka is dedicated to giving back through its Love, Tito's®️ and Vodka for Dog People®️ programs, plus a no-cost farmers market for employees at its Fourteen Acres™️ Farm.",
      "htmlDescription": "<ul><li><p>Tito's Handmade Vodka is America's</p></li><li><p>Original Craft Vodka produced in Austin,</p></li><li><p>Texas. Tito's is known for its high-quality product, charitable giving, and goal to make people happy while making the world a better place. Tito's is crafted in old-fashioned pot stills, with each batch taste-tested. Exceptionally smoot</p></li><li><p>h with an impeccably clean finish, our unflavored, low-calorie vodka is six times distilled, made from corn, and naturally gluten-free with no carbs or sugar*. From a Bloody Mary at brunch, a Transfusion on the golf course, or a simple Tito's and soda with friends, make every occasion a celebration with Tito's! Tito's Handmade Vodka turns spirits into love and goodness with Love, Tito's, the philanthropic heart of the company, supporting thousands of nonprofit organizations across the U.S. — and around the world — amplifying their missions of disaster relief and response, community building, animal welfare, veteran services, and so much more. Available in Liter, 1.75L, 750mL, 375mL, 200mL, and 50mL sizes. For more information, visit titosvodka.com.</p></li></ul><p>*(Average Analysis per 1.5 oz Tito's Handmade Vodka: 98 calories, Carbohydrates 0 grams, Protein 0 grams, Fat 0 grams, Sugar 0 grams)</p><p>MADE IN BATCHES: Tito's Handmade Vodka is made in Austin, Texas, and distilled in old-fashioned pot stills, with each batch taste-tested.</p><p>MADE FROM CORN: Our unflavored vodka is distilled from corn, making it naturally gluten-free. Tito's is 98 calories per 1.5 oz serving, and 65 calories per 1 oz serving.</p><p>MIXES WITH EVERYTHING: Tito's mixes with everything, from a classic Tito's Soda Lime to the iconic Bloody Mary to a refreshing Tito's Transfusion, the official drink of the green.</p><p>SPREAD THE LOVE: Tito's Handmade Vodka is dedicated to giving back through its Love, Tito's®️ and Vodka for Dog People®️ programs, plus a no-cost farmers market for employees at its Fourteen Acres™️ Farm.</p>",
      "tastingNotes": "Exceptionally Smooth. Distilled from corn, Tito's offers a taste that leads with smoky notes of roasted grain and black pepper and finishes with a subtle sweetness. Our gluten-free vodka is crafted for spirit connoisseurs and taste-tested to make sure you get the best juice we have to offer.",
      "images": [
        "https://assets.liquidcommerce.co/catalog/img/3d972802-7f88-410a-a6d7-15e3267f569a.png",
        "https://assets.liquidcommerce.co/catalog/images/2023_Evergreen_LoveTitos_3000x3000.jpg",
        "https://assets.liquidcommerce.co/catalog/images/2023_Evergreen_GoesDownSmooth_3000x3000.jpg",
        "https://assets.liquidcommerce.co/catalog/images/2023_Evergreen_Corn_3000x3000.jpg",
        "https://assets.liquidcommerce.co/catalog/images/image_-_2024-12-18T181404.457_(1).png",
        "https://assets.liquidcommerce.co/catalog/images/(Image_4)_Evergreen_AustinTexas_3000x3000.png",
        "https://assets.liquidcommerce.co/catalog/images/(Image_5)_Evergreen_Cocktails_3000x3000.png"
      ],
      "abv": "40",
      "proof": "80",
      "age": "",
      "availableFrom": null,
      "sizes": [
        {
          "id": "6554c9a46b741e7ad37bc5db",
          "upc": "00619947000020",
          "size": "750 ML",
          "volume": "750",
          "catPath": "SPIRITS > VODKA > REGULAR VODKA",
          "uom": "MILLILITRE",
          "container": "Bottle",
          "containerType": "Glass",
          "pack": false,
          "packDesc": "",
          "image": "https://assets.liquidcommerce.co/catalog/img/3d972802-7f88-410a-a6d7-15e3267f569a.png",
          "attributes": {
            "presale": {
              "canPurchaseOn": null,
              "estimatedShipBy": null,
              "language": "",
              "isActive": false
            },
            "engraving": {
              "maxCharsPerLine": 16,
              "maxLines": 2,
              "fee": 5000,
              "status": true,
              "location": "Above the Label, Front of the Bottle"
            },
            "maxQuantityPerOrder": 12
          },
          "variants": [
            {
              "partNumber": "00619947000020_retailerId-123",
              "retailerId": "retailerId_123",
              "modalities": [
                "shipping"
              ],
              "price": 1799,
              "salePrice": 0,
              "stock": 1878,
              "isEngravable": true,
              "fulfillmentTypes": {
                "shipping": "fulfillmentId_123",
                "onDemand": ""
              },
              "fulfillments": [
                "fulfillmentId_123"
              ]
            }
          ],
          "salsifyPid": "926",
          "maxQuantityPerOrder": 12
        }
      ],
      "attributes": {
        "brandOrigin": "Tito's Handmade Vodka was founded by sixth-generation Texan, Tito Beveridge. His career track took a few turns, but he always found time to do what he loved: make people smile with spirits. Tito got a kick out of infusing vodka for friends and handing out bottles at parties. He quickly became known as \"the vodka guy.\" Willing to risk it all, he pursued the career of his dreams and set out to build a distillery. With a dog by his side, Tito found a plot of land in rural Austin, convinced a few friends to help him build a shack for his still and, against all odds, perfected his pot-distilled spirit. He fought Texas laws, took on nearly $90,000 of debt, and for several years, played a one-man show to get his dream going, overseeing all distilling, hand-bottling, and selling during the hours in between until he sold his first case. Over twenty-five years later, Tito's Handmade Vodka has remained true to its roots and is celebrated for its high-quality product, charitable contributions, and its goal to make people happy while making the world a better place.",
        "originStatement": "Tito's Handmade Vodka was founded in 1997 by sixth-generation Texan, Tito Beveridge. Twenty-five years later, Tito's has remained true to its roots and is celebrated for its high-quality product, charitable contributions, and goal to make people happy while making the world a better place.",
        "ownershipType": [],
        "tags": [],
        "images": {
          "backOfBottle": "",
          "frontOfBottle": "",
          "lifestyle": [
            "https://assets.liquidcommerce.co/catalog/images/2023_Evergreen_LoveTitos_3000x3000.jpg",
            "https://assets.liquidcommerce.co/catalog/images/2023_Evergreen_GoesDownSmooth_3000x3000.jpg",
            "https://assets.liquidcommerce.co/catalog/images/2023_Evergreen_Corn_3000x3000.jpg",
            "https://assets.liquidcommerce.co/catalog/images/image_-_2024-12-18T181404.457_(1).png",
            "https://assets.liquidcommerce.co/catalog/images/(Image_4)_Evergreen_AustinTexas_3000x3000.png",
            "https://assets.liquidcommerce.co/catalog/images/(Image_5)_Evergreen_Cocktails_3000x3000.png"
          ]
        },
        "recipes": [
          {
            "image": "",
            "ingredients": [
              {
                "name": "Tito's Handmade Vodka",
                "amount": "1.5 oz"
              },
              {
                "name": "Ginger Beer",
                "amount": "3 oz"
              },
              {
                "name": "Fresh Lime Juice",
                "amount": "0.5 oz"
              },
              {
                "name": "Lime Slice",
                "amount": "Garnish"
              }
            ],
            "steps": [
              "Add all ingredients to a Tito's Copper Mug with ice.",
              "Stir and garnish with a lime slice."
            ],
            "title": "TITO'S AMERICAN MULE"
          }
        ],
        "video": [
          {
            "link": "goOVywpBvPA",
            "image": "",
            "title": "The Story of Tito's Handmade Vodka"
          }
        ],
        "tastingNotes": [],
        "awards": []
      },
      "priceInfo": {
        "currency": "USD",
        "minimum": 1699,
        "average": 2320,
        "maximum": 3247
      }
    }
    curl --location 'https://staging.api.liquidcommerce.cloud/catalog/search' \
    --header 'Authorization: Bearer <YOUR_ACCESS_TOKEN>' \
    --header 'Content-Type: application/json' \
    --data '{
        "search": "",
        "pageToken": "",
        "entity": "",
        "page": 0,
        "perPage": 10,
        "orderBy": "price",
        "orderDirection": "desc",
        "filters": [
            {
                "key": "categories",
                "values": [
                    "SPIRITS > TEQUILA"
                ]
            },
            {
                "key": "engraving",
                "values": "YES"
            },
             {
                "key": "fulfillment",
                "values": [
                    "onDemand"
                ]
            },
             {
                "key": "tags",
                "values": [
                    "WOMAN OWNED"
                ]
            }
        ],
        "loc": {
            "address": {
                "one": "100 madison ave",
                "two": "apt 1707",
                "city": "New york",
                "state": "NY",
                "zip": "10016"
            }
        },
        "isLegacy": true,
        "isLean": false,
        "refresh": false
    }
    '
    {
      "statusCode": 200,
      "message": "Liquid Catalog, unique AI driven product discovery and recommendations.",
      "metadata": {
        "languages": ["en"],
        "timestamp": 1731603976867,
        "timezone": "UTC",
        "requestId": "requestid_123abc456def",
        "path": "/api/catalog/search",
        "version": "1.7.0"
      },
      "navigation": {
        "correctedQuery": "",
        "attributionToken": "attr123",
        "currentPage": 0,
        "totalPages": 1,
        "totalCount": 2,
        "availableOrderBy": ["price"],
        "availableOrderDirection": ["asc", "desc"],
        "cursor": {
          "nextPageToken": "next123",
          "previousPageToken": "prev123"
        },
        "filters": [
          {
            "bucket": "brands",
            "values": [
              {
                "value": "CASA DRAGONES",
                "count": 2
              }
            ]
          }
        ]
      },
      "products": [
         {
            "id": "30d851c7dab529f303f4931b",
            "salsifyGrouping": "GROUPING-1445173",
            "name": "TEQUILA CASA DRAGONES AÑEJO BARREL BLEND",
            "brand": "CASA DRAGONES",
            "catPath": "Spirits > Tequila > Añejo",
            "category": "",
            "classification": "",
            "type": "",
            "subType": "",
            "region": "Jalisco",
            "country": "Mexico",
            "material": "Agave",
            "color": "White",
            "flavor": "",
            "variety": "",
            "appellation": "",
            "abv": "40",
            "proof": "80",
            "age": "2 Year",
            "vintage": "",
            "description": "Casa Dragones Barrel Blend, 100% Blue Agave Añejo tequila, achieves its distinctive character from being matured in two different wood barrels, new French Oak and new American Oak, each selected for their individual flavor and characteristics. At the end of the aging process, both barrel styles are blended together to create a uniquely smooth, agave-forward taste profile.",
            "htmlDescription": "<p>Casa Dragones Barrel Blend, 100% Blue Agave Añejo tequila, achieves its distinctive character from being matured in two different wood barrels, new French Oak and new American Oak, each selected for their individual flavor and characteristics. At the end of the aging process, both barrel styles are blended together to create a uniquely smooth, agave-forward taste profile.</p>",
            "tastingNotes": ""A subtle melange of flavors." - Wine Spectator",
            "images": [
                "https://example.com/images/product1.jpg"
            ],
            "sizes": [
                {
                    "id": "6554c9a46b741e7ad37c8ad2",
                    "upc": "00850005002161",
                    "size": "750 ML",
                    "volume": "750",
                    "uom": "MILLILITRE",
                    "container": "Bottle",
                    "containerType": "",
                    "pack": false,
                    "packDesc": "",
                    "image": "https://example.com/images/bottle1.jpg",
                    "attributes": {
                        "engraving": {
                            "status": true,
                            "maxLines": 3,
                            "maxCharsPerLine": 16,
                            "fee": 5000,
                            "location": "Between the Labels"
                        }
                    },
                    "variants": [
                        {
                            "partNumber": "00850005002161_6565f4e8700628ce19106bc7",
                            "retailerId": "6565f4e8700628ce19106bc7",
                            "modalities": [
                                "shipping"
                            ],
                            "price": 14999,
                            "salePrice": 0,
                            "stock": 100,
                            "isEngravable": false,
                            "fulfillmentTypes": {
                                "shipping": "65830af0be8824843febdb8c",
                                "onDemand": ""
                            },
                            "fulfillments": [
                                "65830af0be8824843febdb8c"
                            ]
                        }                 
                    ],
                    "salsifyPid": "2216260"
                }
            ],
            "attributes": {
                "brandOrigin": "",
                "originStatement": "The wood used for their new French Oak barrels is a proprietary blend of 100% Quercus Sessile Oak, sustainably sourced from five different forests in the centre of France, then custom toasted to impart roundness and light spicy notes, while respecting the minerality of the soil. The new American Oak barrels receive a custom medium toast, imparting the complexity of the agave and a beautiful aromatic intensity.",
                "ownershipType": [
                    "Woman Owned"
                ],
                "tags": [
                    "Woman Owned"
                ],
                "images": {
                    "backOfBottle": "",
                    "frontOfBottle": "",
                    "lifestyle": []
                },
                "awards": [],
                "recipes": [
                    {
                        "image": "",
                        "ingredients": [
                            {
                                "name": "Casa Dragones Añejo Barrel Blend",
                                "amount": "2 oz."
                            },
                            {
                                "name": "Vanilla Agave Syrup",
                                "amount": "1/4 oz."
                            },
                            {
                                "name": "Bittermens Mole Bitters",
                                "amount": "2 dashes"
                            }
                        ],
                        "steps": [
                            "Stir with ice and strain into a chilled rocks glass with one large ice cube.",
                            "Garnish with a long mandarin orange twist."
                        ],
                        "title": "El Grito"
                    }
                ],
                "video": [],
                "tastingNotes": [
                    {
                        "statement": "Light caramel, with bright hues and pronounced legs.",
                        "image": "https://example.com/images/tasting1.png",
                        "title": "Body & Color"
                    },
                    {
                        "statement": "Fresh floral, pear with notes of figs and almonds.",
                        "image": "https://example.com/images/tasting2.png",
                        "title": "Aroma"
                    },
                    {
                        "statement": "Notes of macadamia, nutmeg and blackberry.",
                        "image": "https://example.com/images/tasting3.png",
                        "title": "Taste"
                    },
                    {
                        "statement": "Long round finish, notes of cacao, spicy black pepper.",
                        "image": "https://example.com/images/tasting4.png",
                        "title": "Finish"
                    }
                ]
            }
        },
        {
          "id": "66ae3111e2e91f45afac28f7",
          "salsifyGrouping": "GROUPING-330410",
          "name": "Tequila Casa Dragones Reposado Mizunara",
          "brand": "Casa Dragones",
          "catPath": "Spirits > Tequila > Reposado",
          "region": "Jalisco",
          "country": "Mexico",
          "material": "Agave",
          "color": "Tawny/brown",
          "variety": "100% Blue Agave",
          "appellation": "Jalisco",
          "abv": "40",
          "proof": "80",
          "age": "1 Year",
          "description": "Casa Dragones Reposado Mizunara, 100% Blue Agave Reposado tequila; is the first tequila rested exclusively in new Mizunara casks, a rare oak native to Japan, traditionally used for aging Japanese whiskies.",
          "images": [
            "https://example.com/images/product2.jpg"
          ],
          "sizes": [
            {
              "id": "4efe5a4554660ad190c99d1c",
              "upc": "00850005002215",
              "size": "750 ML",
              "volume": "750",
              "uom": "MILLILITRE",
              "container": "Bottle",
              "image": "https://example.com/images/size2.jpg",
              "attributes": {
                "engraving": {
                  "status": true,
                  "maxLines": 3,
                  "maxCharsPerLine": 16,
                  "fee": 5000,
                  "location": "Between the Labels"
                }
              },
              "variants": [
                {
                  "partNumber": "8222419_b8fd6f32e6a47930f717c111",
                  "retailerId": "c2c8a24ee2b876280e5e0fa3",
                  "modalities": ["onDemand"],
                  "price": 15999,
                  "salePrice": 0,
                  "stock": 100,
                  "isEngravable": false,
                  "fulfillments": ["26978cee5037ead268f3c0cc"]
                }
              ]
            }
          ],
          "attributes": {
            "tastingNotes": [
              {
                "statement": "Light, bright golden with a silky texture, and long pronounced legs.",
                "image": "https://example.com/images/tasting3.png",
                "title": "Body & Color"
              },
              {
                "statement": "Orange blossom, magnolia with gentle notes of honey and sandalwood.",
                "image": "https://example.com/images/tasting4.png",
                "title": "Aroma"
              }
            ]
          }
        }
      ],
      "retailers": [
        {
          "id": "ret_abc123xyz789",
          "name": "LiquidCommerce Wine & Spirits",
          "platformFee": 499,
          "address": {
            "one": "240 Loisaida Avenue",
            "two": "",
            "city": "New York",
            "state": "NY",
            "zip": "10009",
            "country": "US"
          },
          "fulfillments": [
            {
              "id": "ful_ghi189rst123",
              "timezone": "America/New_York",
              "type": "onDemand",
              "canEngrave": false,
              "fees": {
                "min": 1999,
                "fee": 0,
                "free": {
                  "active": false,
                  "min": 0
                }
              },
              "expectation": {
                "detail": "Arrives in 60 mins",
                "short": "60 mins"
              },
              "hours": {
                "monday": {
                  "active": true,
                  "times": [
                    {
                      "startsAt": "10:00",
                      "endsAt": "21:00"
                    }
                  ]
                },
                "tuesday": {
                  "active": true,
                  "times": [
                    {
                      "startsAt": "10:00",
                      "endsAt": "21:00"
                    }
                  ]
                },
                "wednesday": {
                  "active": true,
                  "times": [
                    {
                      "startsAt": "10:00",
                      "endsAt": "21:00"
                    }
                  ]
                },
                "thursday": {
                  "active": true,
                  "times": [
                    {
                      "startsAt": "10:00",
                      "endsAt": "21:00"
                    }
                  ]
                },
                "friday": {
                  "active": true,
                  "times": [
                    {
                      "startsAt": "10:00",
                      "endsAt": "21:00"
                    }
                  ]
                },
                "saturday": {
                  "active": true,
                  "times": [
                    {
                      "startsAt": "10:00",
                      "endsAt": "21:00"
                    }
                  ]
                },
                "sunday": {
                  "active": true,
                  "times": [
                    {
                      "startsAt": "10:00",
                      "endsAt": "21:00"
                    }
                  ]
                }
              },
              "breaks": [],
              "items": []
            }
          ]
        },
        {
          "id": "ret_abc123xyz189",
          "name": "LiquidCommerce Barn",
          "platformFee": 499,
          "address": {
            "one": "1000 N 5th Ave",
            "two": "134",
            "city": "Vernon Hills",
            "state": "NY",
            "zip": "10061",
            "country": "US"
          },
          "fulfillments": [
            {
              "id": "ful_abc123xyz189",
              "timezone": "America/Chicago",
              "type": "shipping",
              "canEngrave": true,
              "fees": {
                "pack": {
                  "active": true,
                  "maxQuantity": 25,
                  "fee": 1599
                },
                "individual": {
                  "active": true,
                  "maxQuantity": 25,
                  "fee": 1599
                },
                "free": {
                  "active": false,
                  "min": 0
                }
              },
              "expectation": {
                "detail": "Ships in 2-3 days",
                "short": "2-3 days"
              },
              "hours": {
                "monday": {
                  "active": false,
                  "times": []
                },
                "tuesday": {
                  "active": false,
                  "times": []
                },
                "wednesday": {
                  "active": false,
                  "times": []
                },
                "thursday": {
                  "active": false,
                  "times": []
                },
                "friday": {
                  "active": false,
                  "times": []
                },
                "saturday": {
                  "active": false,
                  "times": []
                },
                "sunday": {
                  "active": false,
                  "times": []
                }
              },
              "breaks": [],
              "items": []
            }
          ]
        }
      ]
    }
    ProductSizeAttributes
    Modalities
    Variant
    AttributesAward
    AttributesRecipe
    AttributesVideo
    AttributesTastingNote
    AttributesPersonalization
    VariantFulfillmentTypes
    Fulfillment

    Unique identifier for the API request. Used for debugging and support

    path

    string

    API path

    version

    string

    API version used for the request

    filterParameters
    locType
    navigationSchema
    productType
    retailerType

    Cart

    A full reference to a cart type for different Liquid Commerce APIs.

    CartType

    Attribute
    Description

    id: string

    unique cart identifier

    quantity: number

    CartItem

    Attribute
    Description

    CustomerPlacement

    Attribute
    Description

    CartRetailer

    Attribute
    Description

    CartAttributes

    Attribute
    Description

    CartEvent

    Attribute
    Description

    CartEventTypes

    ENUM VALUES

    CartAttributesPromoCode

    Attribute
    Description

    CartAttributesAmounts

    Attribute
    Description

    CartAttributesAmountsFees

    Attribute
    Description

    CartAttributesAmountsDiscounts

    Attribute
    Description

    CartItemAttributes

    Attribute
    Description

    CartItemEngraving

    Attribute
    Description

    CartItemGiftCart

    Attribute
    Description

    Sample cart

    Cart Object

    optional Salsify grouping identifier

    salsifyPid: string [optional]

    optional Salsify product identifier

    partNumber: string

    retailer's part number

    upc: string

    universal product code

    name: string

    product name

    brand: string

    product brand

    size: string

    product size

    volume: string

    product volume

    uom: string

    unit of measure

    catPath: string

    category path

    abv: string

    alcohol by volume, ex: 40 (40%)

    proof: string

    alcohol proof

    container: string

    product container, ex: Bottle

    containerType: string

    product container type, ex: Glass

    customerPlacement:

    Indicates fulfillment type

    pack: boolean

    whether the product is a pack, ex: true

    packDesc: string

    if the product is a pack and a description is available, ex: 8pk

    quantity: number

    quantity of item

    maxQuantity: number

    maximum allowed quantity

    unitPrice: number

    price per unit

    price: number

    total price for quantity

    scheduleFor: string | Date

    scheduled delivery date/time

    availableAt: string | Date

    availability date/time

    images: Array<string>

    Product images

    mainImage: string

    primary product image

    attributes:

    item-specific attributes

    retailer's engraving fee

    subtotal: number

    Current subtotal for retailer items

    total: number

    Total amount including all fees and taxes

    address:

    location information split out to individual values for the street, city, state, zip code and country

    fulfillments: Array<>

    retailer available fulfillment configurations

    NoItemsInCart

    InvalidId

    NoId

    CartCheckoutProcessed

    NewCart

    CartError

    ItemQuantityChange

    ItemIdNotFound

    ItemsRemoved

    RetailerFulfillmentInvalid

    MaxQuantityPerOrderExceeded

    RetailerOnDemandHoursNotAvailable

    CouponProcessingError

    CouponNotFound

    CouponExpired

    NoApplicableDiscount

    CouponNotStarted

    MinimumOrderValueNotMet

    MinimumOrderUnitsNotMet

    MinimumDistinctItemsNotMet

    QuotaExceeded

    UserLimitExceeded

    NotFirstPurchase

    InvalidCoupon

    InvalidMembership

    InvalidDomain

    InvalidRequirements

    InvalidOrganization

    PresaleItemsNotAllowed

    ProductNotEligible

    NotEnoughPreviousOrders

    RetailerDoesNotAllowPromos

    RetailerDoNotAllowPromos

    RetailerDoesNotAllowGiftCards

    RetailerDoNotAllowGiftCards

    engraving placement

    lines: Array<string>

    engraving text content

    total number of items in cart

    platformFee: number

    platform fee for the cart

    deliveryFee: number

    total delivery fees

    engravingFee: number

    total engraving fees

    shippingFee: number

    total shipping fees

    discounts: number

    total discount fees

    giftCardTotal: number

    total value of applied gift cards

    subtotal: number

    cart subtotal before fees/discounts

    total: number

    final cart total

    isPresaleLocked: boolean

    indicates if the cart is locked to a single presale item

    presaleExpiresAt: Date | null

    the timestamp when the presale lock expires

    createdAt: Date

    cart creation timestamp

    updatedAt: Date

    last update timestamp

    items: Array<CartItem>

    array of cart items

    loc: LocType

    location information

    retailers: Array<CartRetailer>

    array of retailers for items

    attributes: CartAttributes

    cart-level attributes

    events: Array<CartEvent>

    cart-related events, Cart Events

    id: string

    identifier of the item

    retailerId: string

    identifier of retailer providing item

    fulfillmentId: string

    identifier of fulfillment method

    variantId: string

    product variant identifier

    liquidId: string

    internal LiquidCommerce product identifier

    standard: string

    Item in stock and ready to ship

    back_order: string

    Item out of stock, fulfillment upon restock

    pre_sale: string

    Item can be purchased now, ships on release date

    id: string

    retailer identifier

    name: string

    retailers name, ex: Liquid Wine and Spirits

    platformFee: number

    platform fee for retailer

    deliveryFee: number

    retailer's delivery fee

    shippingFee: number

    retailer's shipping fee

    promoCode: CartAttributesPromoCode

    applied promotional code

    amounts: CartAttributesAmounts

    cart amount calculations

    type: CartEventTypes

    type of cart event

    message: string

    event description

    items: Array<Partial<CartItem>>

    affected items if applicable

    OutOfStock

    PresaleLimitExceeded

    PresaleNotStarted

    PresaleExpired

    PresaleMixedCart

    ItemsRequestedNotAdded

    ItemEngravingError

    AddressChange

    RemovedExistingCartItems

    RetailerMinNotMet

    value: string

    the promotional code value

    discount: number

    the discount promo code number

    freeDelivery: boolean

    whether promo provides free delivery

    freeServiceFee: boolean

    whether promo waives service fees

    freeShipping: boolean

    whether promo provides free shipping

    fees: CartAttributesAmountsFees

    fee calculations

    discounts: CartAttributesAmountsDiscounts

    Discount calculations

    shipping: number

    total shipping fees

    onDemand: number

    total on-demand delivery fees

    shipping: number

    shipping discounts

    onDemand: number

    on-demand delivery discounts

    engraving: number

    engraving discounts

    service: number

    service fee discounts

    products: number

    product discounts

    engraving: CartItemEngraving

    Engraving options/configuration

    giftCard: CartItemGiftCart

    Gift card options

    presale: ProductPresale

    Representing a product presale

    isEngravable: boolean

    whether item can be engraved

    hasEngraving: boolean

    whether engraving is applied

    fee: boolean

    engraving service fee

    maxCharsPerLine: number

    maximum characters per line

    maxLines: number

    maximum number of lines

    sender: string

    the sender of the gift

    message: string

    the message attached to the gift

    recipients: Array<string>

    the list of recipients of the gift

    sendDate: string

    the date when the gift should be sent

    salsifyGrouping: string [optional]

    engravingFee: number

    location: string

    {
            "id": "cart_abc123xyz789",
            "quantity": 1,
            "platformFee": 499,
            "deliveryFee": 0,
            "shippingFee": 1599,
            "engravingFee": 0,
            "discounts": 0,
            "giftCardTotal": 0,
            "subtotal": 5999,
            "total": 8097,
            "createdAt": "2024-11-14T19:00:45.433Z",
            "updatedAt": "2024-11-14T19:00:45.433Z",
            "items": [
                {
                    "id": "item_abc123xyz789",
                    "variantId": "var_abc123xyz789",
                    "liquidId": "liq_abc123xyz789",
                    "retailerId": "ret_abc123xyz789",
                    "partNumber": "pn_abc123xyz789",
                    "fulfillmentId": "ful_abc123xyz789",
                    "upc": "88320002003",
                    "catPath": "WINE > ROSE WINE",
                    "volume": "1.5",
                    "uom": "LITRE",
                    "pack": false,
                    "packDesc": "",
                    "container": "Bottle",
                    "containerType": "Bottle",
                    "name": "Whispering Angel Rosé",
                    "brand": "Chateau D'esclans",
                    "scheduledFor": "",
                    "abv": "14",
                    "proof": "28",
                    "size": "1.5 L",
                    "price": 5999,
                    "quantity": 1,
                    "customerPlacement": "standard",
                    "maxQuantity": 12,
                    "unitPrice": 5999,
                    "availableAt": "",
                    "mainImage": "https://storage.example.com/images/products/image1.png",
                    "images": [
                        "https://storage.example.com/images/products/image1.png",
                        "https://storage.example.com/images/products/image2.png",
                        "https://storage.example.com/images/products/image3.png",
                        "https://storage.example.com/images/products/image4.png",
                        "https://storage.example.com/images/products/image5.png"
                    ],
                    "attributes": {
                        "giftCard": {
                            "sender": "",
                            "message": "",
                            "recipients": [],
                            "sendDate": ""
                        },
                        "engraving": {
                            "isEngravable": true,
                            "hasEngraving": false,
                            "maxCharsPerLine": 0,
                            "maxLines": 0,
                            "fee": 0,
                            "location": "",
                            "lines": []
                        }
                    }
                }
            ],
            "loc": {
                "coords": {
                    "lat": 40.7447986,
                    "long": -73.98530819999999
                },
                "address": {
                    "one": "100 madison ave",
                    "two": "apt 1707",
                    "city": "New york",
                    "state": "NY",
                    "zip": "10016",
                    "country": "US",
                    "placesId": "place_abc123xyz789",
                    "customerId": "cust_abc123xyz789",
                    "type": "shipping",
                    "lat": 40.7447986,
                    "long": -73.98530819999999
                }
            },
            "retailers": [
                {
                    "id": "ret_abc123xyz789",
                    "name": "East Houston St Wine & Liquors",
                    "platformFee": 499,
                    "address": {
                        "one": "250 E Houston Street",
                        "two": "",
                        "city": "New York",
                        "state": "NY",
                        "zip": "10002",
                        "country": "US"
                    },
                    "fulfillments": [
                        {
                            "id": "ful_abc123xyz789",
                            "timezone": "America/New_York",
                            "type": "shipping",
                            "canEngrave": false,
                            "fees": {
                                "pack": {
                                    "active": true,
                                    "maxQuantity": 25,
                                    "fee": 1599
                                },
                                "individual": {
                                    "active": true,
                                    "maxQuantity": 25,
                                    "fee": 1599
                                },
                                "free": {
                                    "active": false,
                                    "min": 0
                                }
                            },
                            "expectation": {
                                "detail": "Ships in 2-3 days",
                                "short": "2-3 days"
                            },
                            "hours": {
                                "monday": {
                                    "active": false,
                                    "times": []
                                },
                                "tuesday": {
                                    "active": false,
                                    "times": []
                                },
                                "wednesday": {
                                    "active": false,
                                    "times": []
                                },
                                "thursday": {
                                    "active": false,
                                    "times": []
                                },
                                "friday": {
                                    "active": false,
                                    "times": []
                                },
                                "saturday": {
                                    "active": false,
                                    "times": []
                                },
                                "sunday": {
                                    "active": false,
                                    "times": []
                                }
                            },
                            "breaks": [],
                            "items": [
                                "item_abc123xyz789"
                            ],
                            "engravingFee": 0,
                            "shippingFee": 1599,
                            "deliveryFee": 0,
                            "subtotal": 5999
                        }
                    ],
                    "engravingFee": 0,
                    "deliveryFee": 0,
                    "shippingFee": 1599,
                    "subtotal": 5999,
                    "total": 8097
                }
            ],
            "attributes": {
                "promoCode": {
                    "value": "",
                    "freeDelivery": false,
                    "freeServiceFee": false,
                    "freeShipping": false
                },
                "giftCards": [],
                "amounts": {
                    "fees": {
                        "shipping": 5999,
                        "onDemand": 0
                    },
                    "discounts": {
                        "shipping": 0,
                        "onDemand": 0,
                        "engraving": 0,
                        "service": 0,
                        "products": 0
                    }
                }
            },
            "events": [
                {
                    "type": "NoId",
                    "message": "The cartId provided is empty, a new cart was created",
                    "items": []
                },
                {
                    "type": "PartnerProductConfigs",
                    "message": "Item(s) have been removed, they're currently not available in your account's catalog. Check your LiquidCommerce Partner App account and add the product to you account, or just use our default catalog",
                    "items": [
                        {
                            "partNumber": "pn_abc123xyz789",
                            "quantity": 1,
                            "fulfillmentId": "ful_abc123xyz789",
                            "id": "item_abc123xyz789"
                        }
                    ]
                }
            ]
        }
    CustomerPlacement
    CartItemAttributes
    RetailerAddress
    RetailerFulfillment

    Checkout

    A full reference to a checkout type for the Liquid Commerce Prepare API.

    CheckoutType

    Attribute
    Description

    token: string

    Unique identifier for the checkout session

    cartId: string

    Customer

    Attribute
    Description

    GiftOptions

    Attribute
    Description

    GiftRecipient

    Attribute
    Description

    MarketingPreferences

    Attribute
    Description

    DeliveryTip

    Attribute
    Description

    CheckoutGiftCard

    Attribute
    Description

    CheckoutEvents

    Attribute
    Description

    BillingAddress

    Attribute
    Description

    Checkout BillingAddress

    Attribute
    Description

    CheckoutAmounts

    Attribute
    Description

    AmountsDetails

    Attribute
    Description

    AmountsDetailsTaxes

    Attribute
    Description

    AmountsDetailsDiscounts

    Attribute
    Description

    CheckoutItem

    Attribute
    Description

    ItemAttributes

    Attribute
    Description

    ItemGiftCard

    Attribute
    Description

    ItemEngraving

    Attribute
    Description

    ItemPresale

    Attribute
    Description

    CheckoutRetailer

    Checkout retailer includes accumulated totals using all the same properties from the type for all their available fulfillments. Below are all the values additional to the amounts values.

    Attribute
    Description

    CheckoutRetailerFulfillments

    Checkout retailer fulfillments includes accumulated totals using all the same properties from the type for the fulfillments. Below are all the values additional to the amounts values.

    Attribute
    Description

    CheckoutFulfillmentExpectation

    Attribute
    Context

    DeliveryInstruction

    Attribute
    Context

    Sample checkout

    CheckoutPromoCode

    Attribute
    Description

    Sample checkout

    Checkout Object

    Customer's phone

    birthDate: string

    Customer's birthDate

    profileImage: string

    Customer's profile image

    hasAgeVerify: boolean (moved to level)

    Should the checkout verify age

    createdAt: Date

    Customer's creation time

    updatedAt: Date

    Customer's profile updated time

    Billing address apt, suite, floor, etc

    city: string

    Billing address city

    state: string

    Billing address state, 2 letter code

    zip: string

    Billing address zip code

    country: string

    Billing address country

    Billing address's recipient phone

    one: string

    Billing address street address

    two: string

    Billing address apt, suite, floor, etc

    city: string

    Billing address city

    state: string

    Billing address state, 2 letter code

    zip: string

    Billing address zip code

    country: string

    Billing address country

    Amounts total platform

    discounts: number

    Amounts total discounts

    giftCards: number

    Amounts total giftCards

    tax: number

    Amounts total tax

    tip: number

    Amounts total tip

    total: number

    Amounts total

    details:

    Total amounts details, tax and discount breakdown

    Amounts total product sales tax fee

    Unit of measure

    mainImage: string

    Main product image URL

    unitTax: number

    Tax per unit

    partNumber: string

    Product part number

    fulfillmentId: string

    Item's fulfillment id

    cartItemId: string

    Unique cart item ID

    pack: boolean

    If the product is a pack, then true

    packDesc: string

    Product pack description

    container: string

    Product container, ex: Bottle

    containerType: string

    Product container type, ex: Glass

    customerPlacement:

    Indicates fulfillment type

    name: string

    Product name

    brand: string

    Product brand

    upc: string

    Product upc

    abv: string

    Product's alcohol by volume

    proof: string

    Product's alcohol proof

    volume: string

    Product's volume

    size: string

    Product size

    catPath: string

    Product category path based on the

    quantity: number

    Item's quantity

    unitPrice: number

    Individual item price

    price: number

    Total item price according to the quantity added

    bottleDeposits: number

    Total item's bottle deposit tax fee

    tax: number

    Total item's sales tax

    attributes:

    Item configuration attributes

    fee of the engraving

    lines: string[]

    engraving message lines, ex:

    Amounts total shipping

    delivery: number

    Amounts total delivery

    discounts: number

    Amounts total discounts

    platform : number

    Amounts total platform

    giftCards: number

    Amounts total gifts card

    tax: number

    Amounts total tax

    tip: number

    Amounts total tip

    total: number

    Amounts total

    details:

    Total amounts details, tax and discount breakdown

    address:

    Retailers address

    fulfillments: Array<>

    Retailers fulfillment methods

    Fulfillment item ids

    doesAllowPromos: boolean

    indicates whether the retailer per fulfillment level support promo codes for cart & checkout

    doesAllowGiftCards: boolean

    indicates whether the retailer per fulfillment level support gift cards for checkout

    Associated cart identifier

    customer: Customer

    Customer information

    hasAgeVerify: boolean

    Should the checkout verify age

    hasSubstitutionPolicy: boolean

    Should the checkout allow for substitutions

    isGift: boolean

    When the order is set as gift (isGift is set to true), the system adds gift messaging, special packaging, and gift receipts with optional sender anonymity.

    createdAt: dateString

    Checkout date of creation

    updatedAt: dateString

    Checkout last updated at date

    isPresaleLocked: boolean

    Indicates if the checkout is locked to a single presale item

    presaleExpiresAt: Date | null

    billingSameAsShipping: boolean

    Checkout billing address same as shipping address

    acceptedAccountCreation: boolean

    Whether customer accepted account creation

    giftOptions: GiftOptions

    Checkout gift options

    marketingPreferences: MarketingPreferences

    Checkout marketing opt-ins

    shippingAddress: Address

    Checkout shipping address info, (this is address is propagated from the address set in the cart, if you need to update it you must update the cart. Address changes might produce price changes)

    billingAddress: BillingAddress | Checkout BillingAddress

    Checkout billing address info. BillingAddress information supporting both new and legacy formats. Recommended to use Checkout BillingAddress for new implementations

    amounts: CheckoutAmounts

    Checkout total amounts info

    items: Array<CheckoutItem>

    All checkout items

    retailers: Array<CheckoutRetailer>

    All checkout retailers

    payment: string [optional]

    Payment method identifier

    giftCards:Array<CheckoutGiftCard>

    Gift card codes to apply as payment methods

    events:Array<CheckoutEvents>

    Events related to the checkout process

    promoCode: CheckoutPromoCode

    Promotional code infos to apply a discount to the checkout

    id: string

    Customer's identifier

    firstName: string

    Customer's first name

    lastName: string

    Customer's last name

    email: string

    Customer's email

    company:string

    Customer's company

    message: string

    Checkout gift order message, max length: 500 characters

    recipient: GiftRecipient

    Checkout gift order recipient

    name: string

    Checkout gift order recipient name

    email: string

    Checkout gift order recipient email

    phone: string

    Checkout gift order recipient phone

    canEmail: boolean

    Checkout marketing opt-in for email

    canSms: boolean

    Checkout marketing opt-in for sms

    fulfillmentId: boolean

    Identifier of fulfillment

    tip: number

    The value of the tip

    code: string

    The unique code of the gift card used for identification

    applied: number

    The amount deducted from the gift card during the current transaction

    balance: number

    The remaining balance on the gift card after the applied amount is deducted

    type: string

    The type of the checkout event

    message: string

    A message providing additional context or details about the event

    items: Array<Partial<CheckoutItem>> [optional]

    Array of products details affecting the event

    firstName: string

    Billing address's recipient first name

    lastName: string

    Billing address's recipient last name

    email: string

    Billing address's recipient email

    phone: string

    Billing address's recipient phone

    one: string

    Billing address street address

    id: string

    Billing address's recipient identifier

    firstName: string

    Billing address's recipient first name

    lastName: string

    Billing address's recipient last name

    email: string

    Billing address's recipient email

    company: string

    Billing address's recipient company

    subtotal: number

    Amounts total subtotal

    engraving: number

    Amounts total engraving

    service: number

    Amounts total service

    shipping: number

    Amounts total shipping

    delivery: number

    Amounts total delivery

    taxes: AmountDetailsTaxes

    Amounts total taxes breakdown

    discounts: AmountDetailsDiscounts

    Amounts total discounts breakdown

    bag: number

    Amounts total bag tax fee, ex: Checkout bag fees are required for certain states

    bottleDeposits: number

    Amounts total bottle deposit tax fee, ex: bottle deposit fees are required for certain states

    retailDelivery: number

    Amounts total retail delivery tax fee, only required for the state of Colorado (CO)

    delivery: number

    Amounts total delivery tax fee, for on demand delivery only

    shipping: number

    Amounts total shipping tax fee, for shipping based order only

    engraving: number

    Amounts total engraving fee discounts

    delivery: number

    Amounts total delivery fee discounts, for on demand delivery only

    shipping: number

    Amounts total shipping fee discounts, for shipping based order only

    products: number

    Amounts total product discounts

    service: number

    Amounts total service discounts

    variantId: string

    Unique retailer item ID for the checkout item

    retailerId: string

    Item's retailer id

    liquidId: string

    Internal product identifier

    salsifyPid: string

    Salsify product identifier

    salsifyGrouping: string

    Salsify grouping identifier

    giftCard: ItemGiftCard

    item giftcard configurations

    engraving: ItemEngraving

    item engraving configurations

    presale: ItemPresale

    item presale configurations

    sender: string

    name of the gift card sender

    message: string

    message from the gift card sender

    recipients: string[]

    recipients to receive the gift card

    sendDate: date

    date in which to send the gift card

    isEngravable: boolean

    true when the item allows engraving

    hasEngraving: boolean

    true when the item is engraved

    maxCharsPerLine: number

    maximum of characters per engraving line

    maxLines: number

    max of engraving lines

    location: string

    location of the engraving

    canPurchaseOn: Date | null

    the date when the product can be purchased

    estimatedShipBy: Date | null

    the date when the product is expected to ship

    isActive: boolean

    whether the presale is currently active

    language: string

    the language associated with the product presale

    id: string

    Retailers identifier

    name: string

    Retailers name

    subtotal: number

    Amounts total subtotal

    engraving: number

    Amounts total engraving

    service: number

    Amounts total service

    id: string

    Fulfillment identifier

    scheduledFor: string | Date

    If the fulfillment method is type: onDemand the scheduled date and time in an ISO date string

    deliveryInstructions: string

    Delivery instructions

    type: string

    Fulfillment type, "onDemand" | "shipping"

    expectation: CheckoutFulfillmentExpectation

    Fulfillment expectation configurations

    detail: string

    detailed expectation of fulfillment, ex: Ships in 3 days

    short: string

    short expectation of fulfillment, ex: 3 days

    fulfillmentId: string

    unique identifier for the delivery method

    instructions: string

    delivery guidelines for the selected method, max length: 250 characters

    value: string

    The promotional code value

    discount: number

    The discount promo code number

    freeDelivery: boolean

    Whether promo provides free delivery

    freeServiceFee: boolean

    Whether promo waives service fees

    freeShipping: boolean

    Whether promo provides free shipping

    CheckoutAmounts
    CheckoutAmounts

    phone: string

    two: string

    phone: string

    platform: number

    products: number

    uom: string

    fee: number

    shipping: number

    items: string[]

    Order

    A full reference to a order type for the Liquid Commerce Orders APIs.

    The Order object represents the complete structure of an order in the LiquidCommerce system. It contains comprehensive information about the order including customer details, addresses, items, retailers, fulfillment details, and financial information.

    Core Order Properties

    Property
    Type
    Description

    Customer Information

    Represents customer details associated with the order.

    Property
    Type
    Description

    Address Information

    Basic Address

    Property
    Type
    Description

    Full Address

    Extends the basic address with additional fields.

    Additional Property
    Type
    Description

    Addresses Container

    Property
    Type
    Description

    Order Options

    Represents various order preferences and settings.

    Property
    Type
    Description

    Gift Recipient

    Property
    Type
    Description

    Marketing Preferences

    Property
    Type
    Description

    Order Amounts

    Detailed financial information for the order.

    Property
    Type
    Description

    Tax Details

    Property
    Type
    Description

    Discount Details

    Property
    Type
    Description

    Payment Methods

    Property
    Type
    Description

    Retailer Information

    Represents retailers associated with the order.

    Property
    Type
    Description

    Retailer Address

    Extends the basic address with two properties for coordinates.

    Property
    Type
    Description

    Fulfillment Information

    Represents order fulfillment details.

    Property
    Type
    Description

    Fulfillment Cancellation

    Property
    Type
    Description

    Fulfillment Expectation Formatted

    Property
    Type
    Description

    Fulfillment Package

    Property
    Type
    Description

    Fulfillment Timeline

    Property
    Type
    Description

    Order Item

    Represents individual products in the order.

    Property
    Type
    Description

    Order Product

    Property
    Type
    Description

    Order Product Attributes

    Property
    Type
    Description

    Order Item Pricing

    Property
    Type
    Description

    Order Item Attributes

    Property
    Type
    Description

    Order Item Engraving

    Property
    Type
    Description

    Order Item Gift Card

    Property
    Type
    Description

    Enums

    Order Status

    Order System

    Fulfillment Type

    Package Status

    Customer Placement

    Order Status Flow

    Orders in the LiquidCommerce system typically progress through these statuses:

    1. created - Initial state when an order is first created in the system

    2. processing - Order is actively being prepared/fulfilled

    3. inTransit - Order has been sent out for delivery to the destination

    Special cases:

    • Orders can be canceled from created or processing statuses

    {
        "cartId": "cartId_123abc123abc",
        "hasSubstitutionPolicy": true,
        "isGift": true,
        "customer": {
            "id": "customerId_123abc123abc",
            "firstName": "Jon",
            "lastName": "Doe",
            "email": "[email protected]",
            "company": "ReserveBar",
            "phone": "(601) 952-1325",
            "birthDate": "2003-11-12"
        },
        "billingSameAsShipping": false,
        "shippingAddressTwo": "Apartment 4",
        "acceptedAccountCreation": true,
        "marketingPreferences": {
            "canEmail": true,
            "canSms": true
        },
        "billingAddress": {
            "firstName": "Jon",
            "lastName": "Doe",
            "email": "[email protected]",
            "phone": "(601) 952-1311",
            "company": "ReserveBar",
            "one": "1600 Amphitheatre Parkway",
            "two": "Apartment 1",
            "city": "New york",
            "state": "FL",
            "zip": "10016"
        },
        "giftOptions": {
            "message": "Cheers!",
            "recipient": {
                "name": "User",
                "phone": "(601) 952-1325",
                "email": "[email protected]"
            }
        },
        "hasAgeVerify": false
    }
    CheckoutType
    AmountsDetails
    CustomerPlacement
    Taxonomy
    ItemAttributes
    AmountsDetails
    Address
    CheckoutRetailerFulfillments
    "lines": [
      "Engraving line 1",
      "Engraving line 2"
    ]

    phone

    string | null

    Customer phone

    birthdate

    string | null

    Customer birthdate in YYYY-MM-DD format

    zip

    string

    Zip code

    country

    string

    Country

    company

    string | null

    Billing company

    allowsSubstitution

    boolean

    Does the customer allow product substitution

    billingSameAsShipping

    boolean

    Is billing address same as shipping address

    deliveryInstructions

    string | null

    Delivery instructions

    marketingPreferences

    Marketing preferences

    engraving

    number

    Engraving cost

    service

    number

    Service fee

    delivery

    number

    Delivery fee

    discounts

    number

    Total discounts

    giftCards

    number

    Gift cards amount applied

    tip

    number

    Tip amount

    total

    number

    Order total

    taxDetails

    Tax details

    discountDetails

    Discount details

    bottleDeposits

    number

    Bottle deposits tax

    retailDelivery

    number

    Retail delivery tax

    service

    number

    Service discounts

    code

    string | null

    Gift card code

    timezone

    string

    Retailer IANA timezone

    address

    Retailer address

    amounts

    Retailer amounts

    fulfillments

    Array<>

    Retailer fulfillments

    updatedAt

    string

    Last updated date in ISO format

    itemIds

    Array<string>

    IDs of items in this fulfillment

    cancellation

    Cancellation information

    expectationFormatted

    Delivery expectation formatted

    packages

    Array<>

    Packages for this fulfillment

    timeline

    Array<>

    Fulfillment timeline

    status

    Package status

    dateShipped

    string | null

    Date shipped in ISO format

    liquidId

    string | null

    Liquid ID

    legacyGrouping

    string | null

    Legacy grouping

    legacyPid

    string | null

    Legacy product ID

    customerPlacement

    Customer placement type

    isPresale

    boolean

    Is this a presale item

    expectation

    string | null

    Formatted delivery expectation specific to the item

    estimatedShipBy

    string | null

    Estimated ship by date for presale items

    product

    Product details

    image

    string | null

    Product image URL

    pricing

    Item pricing details

    attributes

    Item attributes

    mskus

    Array<string>

    Product SKUs

    category

    string | null

    Product category

    size

    string | null

    Product size

    volume

    string | null

    Product volume

    uom

    string | null

    Unit of measure

    proof

    string | null

    Product proof

    attributes

    Product attributes

    containerType

    string | null

    Container type

    bottleDeposits

    number

    Bottle deposits amount

    delivered - Order has been successfully delivered to the destination
  • canceled - Order has been canceled (can occur at any stage except delivered)

  • referenceId

    string | null

    Optional order reference ID

    legacyOrderNumber

    string | null

    Optional legacy order number for backward compatibility

    isHybrid

    boolean

    Indicates if this is a hybrid order

    partnerId

    string

    Partner ID associated with the order

    partnerName

    string

    Partner name associated to the order

    createdAt

    string

    Order creation date in ISO format

    updatedAt

    string

    Order last update date in ISO format

    customer

    OrderCustomer

    Customer information

    addresses

    OrderAddresses

    Order addresses (shipping and billing)

    options

    OrderOptions

    Order options including gift details and preferences

    paymentMethods

    Array<PaymentMethods>

    Order payment methods information

    amounts

    OrderAmounts

    Order amount details including subtotal, taxes, fees, etc.

    retailers

    Array<OrderRetailer>

    Order retailers information

    items

    Array<OrderItem>

    Order items details

    id

    string

    Customer ID

    firstName

    string | null

    Customer first name

    lastName

    string | null

    Customer last name

    email

    string

    Customer email

    one

    string

    Address line 1

    two

    string | null

    Address line 2

    city

    string

    City

    state

    string

    State

    firstName

    string | null

    Billing first name

    lastName

    string | null

    Billing last name

    email

    string

    Billing email

    phone

    string | null

    shipping

    FullAddress

    Shipping address

    billing

    FullAddress

    Billing address

    isGift

    boolean

    Is this order a gift

    giftMessage

    string | null

    Gift message

    giftRecipient

    GiftRecipient

    Gift recipient information

    hasVerifiedAge

    boolean

    Has the customer verified their age

    name

    string | null

    Gift recipient name

    email

    string | null

    Gift recipient email

    phone

    string | null

    Gift recipient phone

    email

    boolean

    Email marketing preference

    sms

    boolean

    SMS marketing preference

    subtotal

    number

    Order subtotal

    shipping

    number

    Shipping cost

    platform

    number

    Platform fee

    tax

    number

    Tax amount

    products

    number

    Product tax

    shipping

    number

    Shipping tax

    delivery

    number

    Delivery tax

    bag

    number

    Bag tax

    products

    number

    Product discounts

    shipping

    number

    Shipping discounts

    delivery

    number

    Delivery discounts

    engraving

    number

    Engraving discounts

    type

    string | null

    Payment type, ex: CREDIT_CARD, GIFT_CARD, etc

    card

    string | null

    Card type

    last4

    string | null

    Card last 4 digits

    holder

    string | null

    Card holder

    id

    string

    Retailer ID

    legacyId

    string | null

    Retailer legacy ID

    name

    string

    Retailer name

    system

    ENUM_ORDER_SYSTEM

    Order system type

    latitude

    number | null

    Latitude coordinate

    longitude

    number | null

    Longitude coordinate

    id

    string

    Fulfillment ID

    type

    ENUM_ORDER_FULFILLMENT_TYPE

    Fulfillment type

    status

    ENUM_ORDER_STATUS

    Fulfillment status

    scheduledFor

    string | null

    Scheduled date in ISO format

    category

    string

    Category of cancellation

    subcategory

    string | null

    Subcategory of cancellation

    notes

    string | null

    Specific note left for this cancellation

    detail

    string

    Estimated delivery of a shipping or on-demand fulfillment

    engraving

    string | null

    Estimated delivery for an engraving fulfillment

    id

    string

    Package ID

    carrier

    string | null

    Shipping carrier

    trackingNumber

    string | null

    Tracking number

    trackingUrl

    string | null

    Tracking URL

    status

    ENUM_ORDER_STATUS

    Fulfillment status

    timestamp

    string

    Status timestamp in ISO format

    id

    string

    Item ID

    fulfillmentId

    string | null

    Fulfillment ID

    retailerId

    string

    Retailer ID

    variantId

    string

    Variant ID

    name

    string

    Product name

    brand

    string

    Product brand

    upc

    string

    Product UPC

    sku

    string

    Product SKU

    pack

    boolean

    Is this a pack

    packDescription

    string | null

    Pack description

    abv

    string | null

    Alcohol by volume

    container

    string | null

    Container

    price

    number

    Item price

    unitPrice

    number

    Unit price

    quantity

    number

    Item quantity

    tax

    number

    Item tax

    engraving

    OrderItemEngraving

    Item engraving details

    giftCard

    OrderItemGiftCard

    Item gift card details

    hasEngraving

    boolean

    Has engraving

    fee

    number

    Engraving fee

    location

    string | null

    Engraving location

    lines

    Array<string>

    Engraving text lines

    sender

    string | null

    Gift card sender

    message

    string | null

    Gift card message

    recipients

    Array<string>

    Gift card recipients

    sendDate

    string | null

    Gift card send date

    Billing phone

    enum ENUM_ORDER_STATUS {
      CREATED = 'created',
      PROCESSING = 'processing',
      IN_TRANSIT = 'inTransit',
      CANCELED = 'canceled',
      DELIVERED = 'delivered',
    }
    enum ENUM_ORDER_SYSTEM {
      LIQUIDCOMMERCE = 'LiquidCommerce OMS',
      RESERVEBAR = 'ReserveBar OMS',
    }
    enum ENUM_ORDER_FULFILLMENT_TYPE {
      SHIPPING = 'shipping',
      ON_DEMAND = 'onDemand',
      DIGITAL = 'digital',
      BOPIS = 'bopis'
    }
    enum ENUM_ORDER_PACKAGE_STATUS {
      PENDING = 'pending',
      SHIPPED = 'shipped',
      DELIVERED = 'delivered',
      RETURNED = 'returned',
      CANCELED = 'canceled'
    }
    enum ENUM_CUSTOMER_PLACEMENT {
      STANDARD = 'standard',
      BACK_ORDER = 'back_order',
      PRE_SALE = 'pre_sale'
    }
    MarketingPreferences
    TaxDetails
    DiscountDetails
    RetailerAddress
    Amounts
    Fulfillment
    FulfillmentCancellation
    FulfillmentExpectationFormatted
    FulfillmentPackage
    FulfillmentTimeline
    ENUM_ORDER_PACKAGE_STATUS
    ENUM_CUSTOMER_PLACEMENT
    OrderProduct
    OrderItemPricing
    OrderItemAttributes
    OrderProductAttributes

    Orders

    Technical details for partners integrating with the Event Bridge system to receive real-time order event notifications via webhooks. Our service processes orders and sends it to your provided endpoint

    Prerequisites

    To integrate, our team will work with you to configure:

    1. Your Webhook URL: A secure HTTPS URL endpoint on your system capable of receiving HTTP POST requests with a JSON payload.

    2. Shared Secret (Generated by Us): We will generate a unique, secure secret string for your specific webhook configuration. This secret must be used by you to verify the HMAC signature on incoming requests. We will provide this secret to you securely.

    3. Custom Headers (Optional): You can specify any additional HTTP headers (key-value pairs) you require us to include in the webhook requests (e.g., for static authentication tokens or routing). We will store and send these with each request, provided they don't conflict with essential headers.

    Webhook Request Details

    Our service will send events to your configured Webhook URL using the following specifications:

    • Method: POST

    • Headers:

      • Content-Type: application/json

    Payload Structure (event-type: order)

    The request body is a complex JSON object representing the transformed and serialized order data. The following structure, but may be simplified for documentation clarity. Refer to specific fields relevant to your integration.

    Key Fields & Notes:

    • Identifiers: referenceId, partnerId, retailers[].id, items[].id, etc., are our internal relevant identifiers.

    • Timestamps: All timestamps are in ISO 8601 format (UTC).

    • Payload Granularity: The payload contains details potentially aggregated across multiple internal entities (orders, shipments, fulfillments, retailers). The

    Headers (Recap)

    • Content-Type: application/json

    • User-Agent: liquid-commerce-event-bridge-service/1.0

    • x-liquid-commerce-event-type: e.g., orders

    Expected Partner Response

    Your webhook endpoint must respond promptly to acknowledge receipt.

    • Success: Respond with an HTTP 2xx status code (e.g., 200 OK, 202 Accepted, 204 No Content).

      • Respond immediately after validating the signature (if applicable) and before performing complex/long-running business logic to avoid timeouts. Our service treats any 2xx as success for the delivery attempt.

    Retry Mechanism & DLQ

    If your endpoint:

    1. Responds with a non-2xx status code.

    2. Times out (default: 5000ms).

    3. Experiences a network connectivity issue.

    Our service will automatically retry 3 times with exponential backoff delays: 1000ms, 2000ms, 4000ms (approximately).

    If the event delivery fails after the initial attempt and all 3 retries (total 4 attempts), the original event payload and error details will be sent to our internal Dead Letter Queue (DLQ) which purges after 7 days. No further delivery attempts will be made for that event. Consistent failures indicate an issue with your endpoint that needs investigation.

    Idempotency

    While we have internal mechanisms, the nature of our Distributed Event Streaming System with at-least-once delivery guarantee means you might receive the same logical update via multiple webhook calls.

    It is CRITICAL that your system implements idempotency checks to prevent duplicate processing. Use a combination of identifiers from the payload relevant to your use case. A good candidate is the top-level referenceId combined with a relevant timestamp like updatedAt, or specific fulfillment/package IDs if processing at that level.

    Example Check: Before processing, check if you've already successfully processed an update for referenceId with the same or an earlier updatedAt timestamp. If so, respond 2xx OK but skip processing.

    Security: HMAC Signature Verification

    You must verify the x-liquid-commerce-hmac-sha256 header on every incoming request using the unique Shared Secret we provide.

    • Algorithm: HMAC-SHA256

    • Encoding: Base64

    • Data Signed: The raw, unparsed JSON request body (exactly as received, including whitespace).

    Verification Steps:

    1. Retrieve the raw request body bytes.

    2. Compute the HMAC-SHA256 hash of the raw body using the Shared Secret we provided.

    3. Encode the resulting hash in Base64.

    4. Securely compare (using a timing-safe comparison function) your calculated signature with the value from the x-liquid-commerce-hmac-sha256

    Failure to implement and correctly verify this signature poses a significant security risk, potentially allowing attackers to send fraudulent data to your endpoint.

    Example: Basic Webhook Receiver

    Here are conceptual examples demonstrating the core logic (signature verification, immediate acknowledgment, asynchronous processing) in various languages. These examples focus on the essential security and request handling aspects. Refer to the "Webhook Request Details" section for a comprehensive list of all headers your endpoint will receive, including informational headers like x-liquid-commerce-idempotency-key. Adapt the business logic, error handling, logging, security practices, and asynchronous mechanisms to your specific framework and production needs.

    Node.js (Express)
    Python (Flask)
    Go (net/http)
    Java (Spring Boot)
    PHP

    Support

    If you encounter issues during integration or have questions about the webhook format or behavior, please contact .

    User-Agent: liquid-commerce-event-bridge-service/1.0
  • x-liquid-commerce-event-type: The type of event (e.g., order).

  • x-liquid-commerce-hmac-sha256: The HMAC signature (see Security section).

  • x-liquid-commerce-idempotency-key: A unique identifier for this specific webhook delivery attempt, generated by our service.

  • x-liquid-commerce-delivery-id: A unique identifier for this delivery, constructed from order identifiers and a timestamp.

  • x-liquid-commerce-timestamp: An ISO 8601 timestamp indicating when the webhook was sent by our service.

  • Any custom headers you provided during setup.

  • retailers
    array allows for orders fulfilled by multiple retailers. Each retailer has its own
    fulfillments
    ,
    packages
    , and
    amounts
    .
  • Status Fields: Note the different status enums used at different levels (e.g., fulfillments[].status vs. packages[].status). Use the status most relevant to your needs.

  • Amounts: Amounts are provided at the top level (order total) and broken down within amounts.taxDetails, amounts.discountDetails, and also within each retailers[].amounts. Item-level pricing is in items[].pricing.

  • Optional Fields: Many fields are optional (nullable) depending on the specific order details (e.g., giftMessage, deliveryInstructions, legacyOrderNumber, referenceId). At least referenceId or legacyOrderNumber will be included and for hybrid orders you'll receive both.

  • Additional Headers: Our service includes a few additional headers for traceability and idempotency assistance:

    • x-liquid-commerce-idempotency-key: A unique UUID for each delivery attempt. While you must implement your own idempotency based on payload content (like referenceId and updatedAt), this key can be useful for logging and tracing specific delivery attempts on your end.

    • x-liquid-commerce-delivery-id: A unique identifier for this delivery, typically formed using order identifiers and a timestamp. Useful for tracing.

    • x-liquid-commerce-timestamp: An ISO 8601 timestamp marking when the webhook request was initiated from our service.

  • x-liquid-commerce-hmac-sha256: (If secret provided) Base64 encoded HMAC-SHA256 signature.

  • x-liquid-commerce-idempotency-key: Unique identifier for the delivery attempt.

  • x-liquid-commerce-delivery-id: Unique identifier for the delivery.

  • x-liquid-commerce-timestamp: Timestamp of when the webhook was sent.

  • Any custom headers you specified.

  • Failure: Respond with an HTTP 4xx (Client Error) or 5xx (Server Error) status code if:

    • The signature verification fails (respond with 401 Unauthorized or 400 Bad Request).

    • Your service encounters an error preventing acceptance (e.g., temporary overload, validation error on your side).

    header.
    [email protected]
    {
      referenceId: 'unique-order-ref-123', // Optional: Our internal unique order reference for new services orders
      legacyOrderNumber: 'RBR-LEGACY-456', // Optional: Legacy order number if applicable
      isHybrid: false, // Flag indicating if order involves legacy and new services components
      partnerId: 'partner-id', // Your assigned Partner ID in our system
      partnerName: 'Partner Xyz', // Your partner name in our system
      createdAt: '2023-10-27T10:00:00.000Z', // ISO 8601 timestamp of order creation
      updatedAt: '2023-10-27T10:30:00.000Z', // ISO 8601 timestamp of last relevant update triggering webhook
      customer: {
        id: 'cust-id',
        firstName: 'Jane',
        lastName: 'Doe',
        email: '[email protected]',
        phone: '(212) 290-9820',
        birthdate: '1990-05-15', // YYYY-MM-DD
      },
      addresses: {
        shipping: {
          firstName: 'Jane',
          lastName: 'Doe',
          email: '[email protected]',
          phone: '+15551234567',
          company: null,
          one: '123 Main St',
          two: 'Apt 4B',
          city: 'Anytown',
          state: 'CA',
          zip: '90210',
          country: 'US',
        },
        billing: {
          // ... similar structure, may differ from shipping ...
          firstName: 'Jane',
          lastName: 'Doe',
          email: '[email protected]',
          phone: '+15551234567',
          company: null,
          one: '123 Main St',
          two: 'Apt 4B',
          city: 'Anytown',
          state: 'CA',
          zip: '90210',
          country: 'US',
        },
      },
      options: {
        isGift: true,
        giftMessage: 'Happy Birthday!',
        giftRecipient: {
          name: 'John Smith',
          email: '[email protected]',
          phone: '+15559876543',
        },
        hasVerifiedAge: true,
        allowsSubstitution: false,
        billingSameAsShipping: true,
        deliveryInstructions: 'Leave at front door.',
        marketingPreferences: {
          email: false,
          sms: false,
        },
      },
      amounts: {
        subtotal: 10000,
        shipping: 1000,
        platform: 599, // Fee charged by our platform
        tax: 850,
        engraving: 500,
        service: 200,
        delivery: 0, // Specific delivery fee component
        discounts: 1500, // Total discounts applied
        giftCards: 2500, // Amount paid via gift cards
        tip: 500,
        total: 9150, 
        taxDetails: {
          products: 700,
          shipping: 100,
          delivery: 0,
          bag: 0,
          bottleDeposits: 5,
          retailDelivery: 0,
        },
        discountDetails: {
          products: 1000,
          shipping: 500,
          delivery: 0,
          engraving: 0,
          service: 0,
        },
      },
      paymentMethods: [
        {
          type: 'card', // e.g., card, paypal
          card: 'Visa', // e.g., Visa, Mastercard
          last4: '1234',
          holder: 'Jane Doe',
          code: null, // If a Gift Card was used an abstrct code will be available (ex: 'TER*****FH9W48Y')
        },
      ],
      retailers: [
        {
          id: 'retailer-id-1',
          legacyId: 'legacy-retailer-abc',
          name: 'Best Drinks Store',
          system: 'LiquidCommerce OMS', // Actual values: LiquidCommerce OMS, ReserveBar OMS
          timezone: 'America/Los_Angeles',
          address: {
            one: '456 Side St',
            two: null,
            city: 'Anytown',
            state: 'CA',
            zip: '90211',
            country: 'US',
            coordinates: {
              latitude: 34.0522,
              longitude: -118.2437,
            },
          },
          amounts: {
            // Amounts specific to this retailer's fulfillment
            // ... structure similar to top-level amounts ...
            subtotal: 6000,
            shipping: 500,
            platform: 599,
            tax: 510,
            engraving: 5000,
            service: 120,
            delivery: 0,
            discounts: 1000,
            giftCards: 1000,
            tip: 250,
            total: 5940,
            taxDetails: {
               products: 700,
               shipping: 100,
               delivery: 0,
               bag: 0,
               bottleDeposits: 5,
               retailDelivery: 0,
              },
            },
            discountDetails: {
               products: 1000,
               shipping: 500,
               delivery: 0,
               engraving: 0,
               service: 0,
            },
          },
          fulfillments: [
            {
              id: 'fulfillment-id-xyz',
              type: 'onDemand', // Actual values: shipping, onDemand, digital, bopis
              status: 'processing', // Actual values: created, processing, inTransit, canceled, delivered
              scheduledFor: null, // ISO 8601 if scheduled
              updatedAt: '2023-10-27T10:25:00.000Z',
              cancellation: {
                category: null,
                subcategory: null,
                notes: null,
              },
              expectationFormatted: {
                detail: "Ships in 1-2 days",
                engraving: "Ships in 10 days",
              },
              itemIds: ['item-id-1', 'item-id-2'],
              packages: [
                {
                  id: 'package-id-123',
                  carrier: 'UPS',
                  trackingNumber: '1Z999AA10123456784',
                  trackingUrl: 'https://wwwapps.ups.com/...',
                  status: 'shipped', // Actual values: created, processing, inTransit, canceled, delivered
                  dateShipped: '2023-10-27T10:25:00.000Z',
                },
              ],
              timeline: [
                { status: 'created', timestamp: '2023-10-27T10:00:00.000Z' }, // Actual values for status: created, scheduled, onHold, pending, processing, inTransit, delivered, canceled
                { status: 'processing', timestamp: '2023-10-27T10:15:00.000Z' },
                // Potentially more status updates (inTransit, delivered, etc.)
              ],
            },
            // Potentially multiple fulfillments per retailer if split
          ],
        },
        // Potentially multiple retailers if multi-retailer order
      ],
      items: [
        {
          id: 'item-id-1',
          fulfillmentId: 'fulfillment-id-xyz',
          retailerId: 'retailer-id-1',
          variantId: 'variant-id-1',
          liquidId: 'liquid-id-123',
          legacyGrouping: null,
          legacyPid: 'pid-abc',
          expectation: "Ships in 1-2 days", // expectation formatted for a specific item
          customerPlacement: 'standard', // Actual values for status: standard, pre_sale, back_order
          isPresale: false,
          estimatedShipBy: null,
          product: {
            name: 'Example Wine 750ml',
            brand: 'Example Vineyards',
            upc: '012345678912',
            sku: 'EXWINE750',
            mskus: ['RETAILER123'],
            category: 'Red Wine',
            size: '750ml',
            volume: '750',
            uom: 'ml',
            proof: null,
            attributes: {
              pack: false,
              packDescription: null,
              abv: '13.5',
              container: 'Bottle',
              containerType: 'Glass',
            },
          },
          image: 'https://example.com/image.jpg',
          pricing: {
            price: 2000,
            unitPrice: 2000,
            quantity: 2,
            tax: 340, 
            bottleDeposits: 20, 
          },
          attributes: {
            engraving: {
              hasEngraving: true,
              fee: 5000,
              location: 'Front',
              lines: ['Line 1 Text', 'Line 2 Text'],
            },
            giftCard: {
              // Based on PartnerOrderItemGiftCardSerialization
              sender: 'Jane Doe',
              message: null,
              recipients: ['John Smith <[email protected]>'],
              sendDate: null,
            },
          },
        },
        // ... more items ...
      ],
    }
    import express from 'express';
    import crypto from 'crypto';
    
    const app = express();
    
    // IMPORTANT: Use express.raw middleware to access the raw request body for HMAC verification.
    // Must run *before* express.json() or any other body-parsing middleware.
    app.use(express.raw({ type: 'application/json', limit: '5mb' })); // Adjust limit as needed
    
    const PORT = process.env.PORT || 3000;
    // Store the unique secret WE PROVIDED securely (e.g., in environment variables)
    const WEBHOOK_SECRET = process.env.EVENT_BRIDGE_WEBHOOK_SECRET;
    const HMAC_HEADER = 'x-liquid-commerce-hmac-sha256'; // Use the correct header name
    
    // Your Webhook Endpoint
    app.post('/webhook/event-bridge', (req, res) => {
      console.log(`Received webhook request headers: ${JSON.stringify(req.headers)}`);
    
      // --- 1. Verify Signature (CRITICAL) ---
      if (!WEBHOOK_SECRET) {
        console.error(`${HMAC_HEADER} verification skipped: WEBHOOK_SECRET not configured!`);
        // Consider failing requests if secret is expected but not configured
        return res.status(500).send('Internal Server Error: Webhook secret not configured.');
      }
    
      const receivedSignature = req.header(HMAC_HEADER);
      if (!receivedSignature) {
        console.warn(`Missing ${HMAC_HEADER} header`);
        return res.status(400).send('Bad Request: Missing signature header');
      }
    
      try {
        const expectedSignature = crypto
          .createHmac('sha256', WEBHOOK_SECRET)
          .update(req.body) // Use the raw body buffer from express.raw()
          .digest('base64');
    
        const receivedSigBuffer = Buffer.from(receivedSignature, 'base64');
        const expectedSigBuffer = Buffer.from(expectedSignature, 'base64');
    
        // Use timing-safe comparison
        if (
          receivedSigBuffer.length !== expectedSigBuffer.length ||
          !crypto.timingSafeEqual(receivedSigBuffer, expectedSigBuffer)
        ) {
          console.error('Invalid signature');
          return res.status(401).send('Unauthorized: Invalid signature');
        }
        console.log('Signature verified successfully');
      } catch (error) {
        console.error('Error during signature verification:', error);
        return res.status(500).send('Internal Server Error during signature verification');
      }
    
      // --- 2. Acknowledge Receipt Immediately (Before Parsing/Processing) ---
      // Send a 2xx response quickly.
      res.status(202).send('Accepted');
    
      // --- 3. Parse and Process Asynchronously ---
      // Wrap parsing and processing in a separate async function to avoid blocking.
      handleEventProcessing(req.body)
        .then(() => console.log('Event processing initiated.'))
        .catch((err) => console.error('Failed to initiate event processing:', err));
    });
    
    // Asynchronous function to handle parsing and business logic
    async function handleEventProcessing(rawBodyBuffer) {
      let eventPayload;
      try {
        // Parse the JSON from the raw body buffer
        eventPayload = JSON.parse(rawBodyBuffer.toString('utf-8'));
        // console.log('Parsed payload:', JSON.stringify(eventPayload, null, 2)); // Be careful logging full payload
        console.log(`Parsed payload for referenceId: ${eventPayload?.referenceId}`);
      } catch (error) {
        console.error('Failed to parse JSON payload after acknowledgment:', error);
        // Add monitoring/alerting here. The request was already acknowledged.
        return; // Stop processing if parsing fails
      }
    
      console.log(`Processing event referenceId: ${eventPayload.referenceId}, UpdatedAt: ${eventPayload.updatedAt}`);
    
      // --- Implement Idempotency Check Here ---
      // const alreadyProcessed = await checkIfEventProcessed(eventPayload.referenceId, eventPayload.updatedAt);
      // if (alreadyProcessed) {
      //   console.log(`Event referenceId ${eventPayload.referenceId} already processed or is older. Skipping.`);
      //   return;
      // }
    
      // --- Your Business Logic Here ---
      // e.g., update your database based on eventPayload details...
      // Use eventPayload.retailers[0].fulfillments[0].status or packages[0].status etc.
      try {
        // ... Simulate async work ...
        await new Promise((resolve) => setTimeout(resolve, 100));
        console.log(`Business logic completed for referenceId: ${eventPayload.referenceId}`);
      } catch (businessError) {
        console.error(`Error during business logic for referenceId ${eventPayload.referenceId}:`, businessError);
        // Add monitoring/alerting. Event already acknowledged. May need manual reconciliation.
        return;
      }
    
      // --- Mark event as processed (for idempotency) ---
      // await markEventAsProcessed(eventPayload.referenceId, eventPayload.updatedAt);
    
      console.log(`Successfully processed event referenceId: ${eventPayload.referenceId}`);
    }
    
    app.listen(PORT, () => {
      console.log(`Webhook receiver listening on port ${PORT}`);
      if (!WEBHOOK_SECRET) {
        console.warn(
          `Warning: EVENT_BRIDGE_WEBHOOK_SECRET environment variable not set. ${HMAC_HEADER} verification will be skipped unless the check inside verify_signature fails.`,
        );
      }
    });
    import os
    import hmac
    import hashlib
    import base64
    import json
    import logging
    from flask import Flask, request, abort, make_response
    from threading import Thread
    
    # Configure logging
    logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
    
    app = Flask(__name__)
    
    # Store the unique secret WE PROVIDED securely (e.g., in environment variables)
    WEBHOOK_SECRET = os.environ.get('EVENT_BRIDGE_WEBHOOK_SECRET')
    HMAC_HEADER = 'x-liquid-commerce-hmac-sha256' # Use the correct header name
    
    def verify_signature(req):
        """Verifies the HMAC signature of the request."""
        if not WEBHOOK_SECRET:
            logging.error(f"{HMAC_HEADER} verification skipped: WEBHOOK_SECRET not configured!")
            # Fail closed if secret is expected but missing
            abort(500, description='Internal Server Error: Webhook secret not configured.')
    
        received_signature_b64 = req.headers.get(HMAC_HEADER)
        if not received_signature_b64:
            logging.warning(f"Missing {HMAC_HEADER} header")
            abort(400, description=f'Bad Request: Missing {HMAC_HEADER} header')
    
        # IMPORTANT: Access the raw request body bytes
        raw_body = req.get_data() # Flask specific way to get raw body
    
        try:
            hash_obj = hmac.new(WEBHOOK_SECRET.encode('utf-8'), raw_body, hashlib.sha256)
            expected_signature_b64 = base64.b64encode(hash_obj.digest()).decode('utf-8')
    
            # Use timing-safe comparison
            if not hmac.compare_digest(expected_signature_b64, received_signature_b64):
                logging.error('Invalid signature')
                abort(401, description='Unauthorized: Invalid signature')
    
            logging.info('Signature verified successfully')
            return raw_body # Return raw body for later processing
        except Exception as e:
            logging.error(f"Error during signature verification: {e}", exc_info=True)
            abort(500, description='Internal Server Error during signature verification')
    
    def process_event_async(raw_body_bytes):
        """Parses and processes the event payload asynchronously."""
        try:
            payload_str = raw_body_bytes.decode('utf-8')
            event_payload = json.loads(payload_str)
            reference_id = event_payload.get('referenceId', 'N/A')
            updated_at = event_payload.get('updatedAt', 'N/A')
            logging.info(f"Parsed payload for referenceId: {reference_id}")
            # Careful logging full payload in production
            # logging.debug(f"Full payload: {payload_str}")
    
        except json.JSONDecodeError as e:
            logging.error(f"Failed to parse JSON payload after acknowledgment: {e}", exc_info=True)
            # Add monitoring/alerting here
            return # Stop processing if parsing fails
        except Exception as e:
            logging.error(f"Unexpected error during payload parsing: {e}", exc_info=True)
            return
    
        logging.info(f"Processing event referenceId: {reference_id}, UpdatedAt: {updated_at}")
    
        # --- Implement Idempotency Check Here ---
        # try:
        #     already_processed = check_if_event_processed(reference_id, updated_at)
        #     if already_processed:
        #         logging.info(f"Event referenceId {reference_id} already processed or is older. Skipping.")
        #         return
        # except Exception as e:
        #     logging.error(f"Error during idempotency check for referenceId {reference_id}: {e}", exc_info=True)
        #     # Decide how to handle idempotency check errors (e.g., retry, alert)
        #     return
    
        # --- Your Business Logic Here ---
        try:
            # e.g., update your database based on event_payload details...
            # Simulate work
            import time
            time.sleep(0.1) # Simulate async work
            logging.info(f"Business logic completed for referenceId: {reference_id}")
        except Exception as business_error:
            logging.error(f"Error during business logic for referenceId {reference_id}: {business_error}", exc_info=True)
            # Add monitoring/alerting. Event already acknowledged. May need manual reconciliation.
            return
    
        # --- Mark event as processed (for idempotency) ---
        # try:
        #     mark_event_as_processed(reference_id, updated_at)
        #     logging.info(f"Successfully marked referenceId {reference_id} as processed.")
        # except Exception as e:
        #     logging.error(f"Error marking referenceId {reference_id} as processed: {e}", exc_info=True)
        #     # Alerting is crucial here if marking fails
    
    @app.route('/webhook/event-bridge', methods=['POST'])
    def handle_webhook():
        logging.info(f"Received webhook request headers: {dict(request.headers)}")
    
        # --- 1. Verify Signature (CRITICAL) ---
        # This function calls abort() on failure
        raw_body = verify_signature(request)
    
        # --- 2. Acknowledge Receipt Immediately (Before Parsing/Processing) ---
        # Send a 2xx response quickly.
        response = make_response("Accepted", 202)
    
        # --- 3. Start Asynchronous Processing ---
        # Use threading for simple async background task (for production, consider Celery, RQ, etc.)
        thread = Thread(target=process_event_async, args=(raw_body,))
        thread.start()
        logging.info("Event processing initiated in background thread.")
    
        return response
    
    if __name__ == '__main__':
        port = int(os.environ.get('PORT', 3000))
        if not WEBHOOK_SECRET:
            logging.warning(f"Warning: EVENT_BRIDGE_WEBHOOK_SECRET environment variable not set. {HMAC_HEADER} verification will be skipped unless the check inside verify_signature fails.")
        # Use a production-ready WSGI server like gunicorn or uWSGI instead of app.run in production
        app.run(host='0.0.0.0', port=port)
    
    package main
    
    import (
    	"bytes"
    	"crypto/hmac"
    	"crypto/sha256"
    	"crypto/subtle"
    	"encoding/base64"
    	"encoding/json"
    	"fmt"
    	"io"
    	"log"
    	"net/http"
    	"os"
    	"time"
    )
    
    const hmacHeader = "x-liquid-commerce-hmac-sha256" // Use the correct header name
    var webhookSecret string                          // Store the unique secret WE PROVIDED
    
    func init() {
    	webhookSecret = os.Getenv("EVENT_BRIDGE_WEBHOOK_SECRET")
    	if webhookSecret == "" {
    		log.Printf("Warning: EVENT_BRIDGE_WEBHOOK_SECRET environment variable not set. %s verification will fail.", hmacHeader)
    		// Consider os.Exit(1) if secret is mandatory for startup
    	}
    }
    
    func verifySignature(r *http.Request, rawBody []byte) (bool, error) {
    	if webhookSecret == "" {
    		log.Printf("Error: %s verification skipped: WEBHOOK_SECRET not configured!", hmacHeader)
    		return false, fmt.Errorf("webhook secret not configured") // Fail closed
    	}
    
    	receivedSignatureB64 := r.Header.Get(hmacHeader)
    	if receivedSignatureB64 == "" {
    		log.Printf("Warning: Missing %s header", hmacHeader)
    		return false, fmt.Errorf("missing signature header")
    	}
    
    	mac := hmac.New(sha256.New, []byte(webhookSecret))
    	_, err := mac.Write(rawBody) // Use the raw body bytes
    	if err != nil {
    		log.Printf("Error writing body to HMAC: %v", err)
    		return false, fmt.Errorf("HMAC calculation error")
    	}
    	expectedSignatureBytes := mac.Sum(nil)
    	expectedSignatureB64 := base64.StdEncoding.EncodeToString(expectedSignatureBytes)
    
    	// Decode received signature for timing-safe comparison
    	receivedSignatureBytes, err := base64.StdEncoding.DecodeString(receivedSignatureB64)
    	if err != nil {
    		log.Printf("Error decoding received signature: %v", err)
    		return false, fmt.Errorf("invalid signature format")
    	}
    
    	// Use timing-safe comparison
    	if subtle.ConstantTimeCompare(receivedSignatureBytes, expectedSignatureBytes) == 1 {
    		log.Println("Signature verified successfully")
    		return true, nil
    	}
    
    	log.Println("Invalid signature")
    	// Log expected vs received for debugging (CAUTION: Sensitive in prod logs)
    	// log.Printf("Expected: %s, Received (b64): %s", expectedSignatureB64, receivedSignatureB64)
    	return false, fmt.Errorf("invalid signature")
    }
    
    func handleEventProcessingAsync(rawBodyBytes []byte) {
    	var eventPayload map[string]interface{} // Use a more specific struct in production
    
    	err := json.Unmarshal(rawBodyBytes, &eventPayload)
    	if err != nil {
    		log.Printf("Failed to parse JSON payload after acknowledgment: %v", err)
    		// Add monitoring/alerting here
    		return // Stop processing if parsing fails
    	}
    
    	referenceID := "N/A"
    	updatedAt := "N/A"
    	if refID, ok := eventPayload["referenceId"].(string); ok {
    		referenceID = refID
    	}
    	if updAt, ok := eventPayload["updatedAt"].(string); ok {
    		updatedAt = updAt
    	}
    
    	log.Printf("Parsed payload for referenceId: %s", referenceID)
    	// Careful logging full payload in production
    	// log.Printf("Full payload: %s", string(rawBodyBytes))
    
    	log.Printf("Processing event referenceId: %s, UpdatedAt: %s", referenceID, updatedAt)
    
    	// --- Implement Idempotency Check Here ---
    	// alreadyProcessed, err := checkIfEventProcessed(referenceID, updatedAt)
    	// if err != nil {
    	//     log.Printf("Error during idempotency check for referenceId %s: %v", referenceID, err)
    	//     // Decide how to handle idempotency check errors
    	//     return
    	// }
    	// if alreadyProcessed {
    	//     log.Printf("Event referenceId %s already processed or is older. Skipping.", referenceID)
    	//     return
    	// }
    
    	// --- Your Business Logic Here ---
    	// e.g., update your database based on eventPayload details...
    	// Simulate work
    	time.Sleep(100 * time.Millisecond) // Simulate async work
    	log.Printf("Business logic completed for referenceId: %s", referenceID)
    
    	// --- Mark event as processed (for idempotency) ---
    	// err = markEventAsProcessed(referenceID, updatedAt)
    	// if err != nil {
    	//     log.Printf("Error marking referenceId %s as processed: %v", referenceID, err)
    	//     // Alerting is crucial here
    	// } else {
    	//     log.Printf("Successfully marked referenceId %s as processed.", referenceID)
    	// }
    }
    
    func webhookHandler(w http.ResponseWriter, r *http.Request) {
    	log.Printf("Received webhook request headers: %v", r.Header)
    
    	if r.Method != http.MethodPost {
    		log.Printf("Invalid method: %s", r.Method)
    		http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
    		return
    	}
    
    	// IMPORTANT: Read the raw request body
    	// Limit body size to prevent abuse (e.g., 5MB)
    	r.Body = http.MaxBytesReader(w, r.Body, 5*1024*1024)
    	rawBody, err := io.ReadAll(r.Body)
    	if err != nil {
    		if err.Error() == "http: request body too large" {
    			log.Printf("Request body too large: %v", err)
    			http.Error(w, "Request Entity Too Large", http.StatusRequestEntityTooLarge)
    		} else {
    			log.Printf("Error reading request body: %v", err)
    			http.Error(w, "Internal Server Error", http.StatusInternalServerError)
    		}
    		return
    	}
    	// It's crucial to close the original body, although ReadAll does effectively consume it.
    	// If you were using io.Copy or similar, ensure the original body is closed.
    	defer r.Body.Close()
    
    
    	// --- 1. Verify Signature (CRITICAL) ---
    	valid, sigErr := verifySignature(r, rawBody)
    	if !valid {
    		// Determine appropriate status code based on error
    		statusCode := http.StatusInternalServerError
    		if sigErr != nil {
    			errMsg := sigErr.Error()
    			if errMsg == "missing signature header" {
    				statusCode = http.StatusBadRequest
    			} else if errMsg == "invalid signature format" || errMsg == "invalid signature" {
    				statusCode = http.StatusUnauthorized
    			} else if errMsg == "webhook secret not configured" {
    				statusCode = http.StatusInternalServerError // Or 503 Service Unavailable
    			}
    		}
    		http.Error(w, fmt.Sprintf("%d %s", statusCode, http.StatusText(statusCode)), statusCode)
    		return
    	}
    
    	// --- 2. Acknowledge Receipt Immediately (Before Parsing/Processing) ---
    	// Send a 2xx response quickly.
    	w.WriteHeader(http.StatusAccepted)
    	fmt.Fprintln(w, "Accepted")
    
    	// --- 3. Start Asynchronous Processing ---
    	// Use a goroutine for async background task
    	go handleEventProcessingAsync(rawBody)
    	log.Println("Event processing initiated in background goroutine.")
    }
    
    func main() {
    	port := os.Getenv("PORT")
    	if port == "" {
    		port = "3000"
    	}
    
    	http.HandleFunc("/webhook/event-bridge", webhookHandler)
    
    	log.Printf("Webhook receiver listening on port %s", port)
    	err := http.ListenAndServe(":"+port, nil)
    	if err != nil {
    		log.Fatalf("Failed to start server: %v", err)
    	}
    }
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.http.HttpHeaders;
    import org.springframework.http.HttpStatus;
    import org.springframework.http.ResponseEntity;
    import org.springframework.scheduling.annotation.Async;
    import org.springframework.scheduling.annotation.EnableAsync;
    import org.springframework.stereotype.Component;
    import org.springframework.stereotype.Service;
    import org.springframework.web.bind.annotation.*;
    import org.slf4j.Logger;
    import org.slf4j.LoggerFactory;
    
    import javax.crypto.Mac;
    import javax.crypto.spec.SecretKeySpec;
    import jakarta.servlet.http.HttpServletRequest; // Use jakarta for Spring Boot 3+
    import java.nio.charset.StandardCharsets;
    import java.security.InvalidKeyException;
    import java.security.MessageDigest;
    import java.security.NoSuchAlgorithmException;
    import java.util.Base64;
    import java.util.Objects;
    import com.fasterxml.jackson.core.JsonProcessingException;
    import com.fasterxml.jackson.databind.ObjectMapper;
    import java.util.Map; // Or a specific DTO class
    
    @SpringBootApplication
    @EnableAsync // Enable asynchronous processing
    public class WebhookReceiverApplication {
    
        private static final Logger log = LoggerFactory.getLogger(WebhookReceiverApplication.class);
        // Store the unique secret WE PROVIDED securely (e.g., via @Value or config server)
        private static final String WEBHOOK_SECRET = System.getenv("EVENT_BRIDGE_WEBHOOK_SECRET");
        private static final String HMAC_HEADER = "x-liquid-commerce-hmac-sha256"; // Use the correct header name
        private static final String HMAC_ALGORITHM = "HmacSHA256";
    
        public static void main(String[] args) {
            if (WEBHOOK_SECRET == null || WEBHOOK_SECRET.isEmpty()) {
                 log.warn("Warning: EVENT_BRIDGE_WEBHOOK_SECRET environment variable not set. {} verification will fail.", HMAC_HEADER);
                 // Potentially prevent application startup if secret is mandatory
            }
            SpringApplication.run(WebhookReceiverApplication.class, args);
        }
    
        @RestController
        public static class WebhookController {
    
            private final SignatureVerifier signatureVerifier;
            private final AsyncEventProcessor asyncEventProcessor;
    
            public WebhookController(SignatureVerifier signatureVerifier, AsyncEventProcessor asyncEventProcessor) {
                this.signatureVerifier = signatureVerifier;
                this.asyncEventProcessor = asyncEventProcessor;
            }
    
            // IMPORTANT: Receive raw body as byte array
            @PostMapping("/webhook/event-bridge")
            public ResponseEntity<String> handleWebhook(@RequestBody byte[] rawBody, HttpServletRequest request) {
                log.info("Received webhook request headers: {}", request.getHeaderNames()); // Log header names or specific needed headers
    
                String receivedSignature = request.getHeader(HMAC_HEADER);
    
                // --- 1. Verify Signature (CRITICAL) ---
                if (!signatureVerifier.isValidSignature(rawBody, receivedSignature)) {
                    // SignatureVerifier logs details; determine status code based on internal state/error
                    if (receivedSignature == null) {
                        return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("Bad Request: Missing signature header");
                    } else if (WEBHOOK_SECRET == null || WEBHOOK_SECRET.isEmpty()){
                         return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("Internal Server Error: Webhook secret not configured.");
                    }
                     else {
                        return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Unauthorized: Invalid signature");
                    }
                }
    
                // --- 2. Acknowledge Receipt Immediately (Before Parsing/Processing) ---
                ResponseEntity<String> response = ResponseEntity.status(HttpStatus.ACCEPTED).body("Accepted");
    
                // --- 3. Start Asynchronous Processing ---
                asyncEventProcessor.handleEventProcessing(rawBody);
                log.info("Event processing initiated asynchronously.");
    
                return response;
            }
        }
    
        @Component
        public static class SignatureVerifier {
    
            public boolean isValidSignature(byte[] rawBody, String receivedSignatureB64) {
                 if (WEBHOOK_SECRET == null || WEBHOOK_SECRET.isEmpty()) {
                     log.error("{} verification skipped: WEBHOOK_SECRET not configured!", HMAC_HEADER);
                     // Fail closed if secret is expected but missing
                     return false;
                 }
                if (receivedSignatureB64 == null || receivedSignatureB64.isEmpty()) {
                    log.warn("Missing {} header", HMAC_HEADER);
                    return false;
                }
    
                try {
                    Mac mac = Mac.getInstance(HMAC_ALGORITHM);
                    SecretKeySpec secretKeySpec = new SecretKeySpec(WEBHOOK_SECRET.getBytes(StandardCharsets.UTF_8), HMAC_ALGORITHM);
                    mac.init(secretKeySpec);
                    byte[] expectedSignatureBytes = mac.doFinal(rawBody);
                    // No need to Base64 encode expected here, decode received instead for comparison
    
                    byte[] receivedSignatureBytes = Base64.getDecoder().decode(receivedSignatureB64);
    
                    // Use timing-safe comparison
                    boolean valid = MessageDigest.isEqual(receivedSignatureBytes, expectedSignatureBytes);
                    if (valid) {
                        log.info("Signature verified successfully");
                    } else {
                        log.error("Invalid signature");
                        // String expectedSignatureB64 = Base64.getEncoder().encodeToString(expectedSignatureBytes);
                        // log.debug("Expected B64: {}, Received B64: {}", expectedSignatureB64, receivedSignatureB64); // CAUTION in prod
                    }
                    return valid;
    
                } catch (NoSuchAlgorithmException | InvalidKeyException | IllegalArgumentException e) {
                    log.error("Error during signature verification: {}", e.getMessage(), e);
                    return false; // Treat crypto errors as invalid signature
                }
            }
        }
    
        @Service
        public static class AsyncEventProcessor {
            private final ObjectMapper objectMapper = new ObjectMapper(); // Jackson mapper
    
            @Async // Make this method run in a background thread pool
            public void handleEventProcessing(byte[] rawBodyBytes) {
                 Map<String, Object> eventPayload; // Use a specific DTO class for better type safety
                 String referenceId = "N/A";
                 String updatedAt = "N/A";
    
                 try {
                     eventPayload = objectMapper.readValue(rawBodyBytes, Map.class);
                     // Extract relevant fields safely
                     if(eventPayload.get("referenceId") instanceof String) {
                        referenceId = (String) eventPayload.get("referenceId");
                     }
                     if(eventPayload.get("updatedAt") instanceof String) {
                         updatedAt = (String) eventPayload.get("updatedAt");
                     }
    
                     log.info("Parsed payload for referenceId: {}", referenceId);
                     // Be careful logging full payload in production
                     // log.debug("Full payload: {}", new String(rawBodyBytes, StandardCharsets.UTF_8));
    
                 } catch (JsonProcessingException e) {
                     log.error("Failed to parse JSON payload after acknowledgment: {}", e.getMessage(), e);
                     // Add monitoring/alerting here
                     return; // Stop processing if parsing fails
                 } catch (Exception e) {
                     log.error("Unexpected error during payload parsing: {}", e.getMessage(), e);
                     return;
                 }
    
                 log.info("Processing event referenceId: {}, UpdatedAt: {}", referenceId, updatedAt);
    
                 // --- Implement Idempotency Check Here ---
                 // try {
                 //     boolean alreadyProcessed = checkIfEventProcessed(referenceId, updatedAt); // Inject service dependency
                 //     if (alreadyProcessed) {
                 //         log.info("Event referenceId {} already processed or is older. Skipping.", referenceId);
                 //         return;
                 //     }
                 // } catch (Exception e) {
                 //     log.error("Error during idempotency check for referenceId {}: {}", referenceId, e.getMessage(), e);
                 //     // Decide how to handle idempotency check errors
                 //     return;
                 // }
    
                // --- Your Business Logic Here ---
                try {
                    // e.g., update your database based on eventPayload details...
                    // Simulate work
                    Thread.sleep(100); // Simulate async work
                    log.info("Business logic completed for referenceId: {}", referenceId);
                } catch (InterruptedException e) {
                    Thread.currentThread().interrupt();
                    log.error("Business logic interrupted for referenceId {}: {}", referenceId, e.getMessage());
                     return;
                } catch (Exception businessError) {
                    log.error("Error during business logic for referenceId {}: {}", referenceId, businessError.getMessage(), businessError);
                    // Add monitoring/alerting. Event already acknowledged. May need manual reconciliation.
                     return;
                }
    
                 // --- Mark event as processed (for idempotency) ---
                 // try {
                 //     markEventAsProcessed(referenceId, updatedAt); // Inject service dependency
                 //     log.info("Successfully marked referenceId {} as processed.", referenceId);
                 // } catch (Exception e) {
                 //     log.error("Error marking referenceId {} as processed: {}", referenceId, e.getMessage(), e);
                 //     // Alerting is crucial here
                 // }
            }
        }
    }
    <?php declare(strict_types=1);
    
    // Basic error logging (use a proper logger like Monolog in production)
    error_reporting(E_ALL);
    ini_set('log_errors', '1');
    ini_set('error_log', '/tmp/php_webhook_errors.log'); // Adjust path
    
    // --- Configuration ---
    $webhookSecret = getenv('EVENT_BRIDGE_WEBHOOK_SECRET') ?: ''; // Store the unique secret WE PROVIDED securely
    $hmacHeader = 'x-liquid-commerce-hmac-sha256'; // Use the correct header name
    
    // --- Request Handling ---
    $requestMethod = $_SERVER['REQUEST_METHOD'] ?? 'GET';
    $headers = getallheaders(); // Get all request headers
    
    // Log headers (be careful in production)
    // file_put_contents('php://stderr', 'Received headers: ' . json_encode($headers) . PHP_EOL);
    
    if ($requestMethod !== 'POST') {
        error_log('Invalid method: ' . $requestMethod);
        http_response_code(405); // Method Not Allowed
        echo 'Method Not Allowed';
        exit;
    }
    
    // --- 1. Verify Signature (CRITICAL) ---
    if (empty($webhookSecret)) {
        error_log("{$hmacHeader} verification skipped: WEBHOOK_SECRET not configured!");
        http_response_code(500);
        echo 'Internal Server Error: Webhook secret not configured.';
        exit;
    }
    
    $receivedSignatureB64 = $headers[$hmacHeader] ?? '';
    if (empty($receivedSignatureB64)) {
        error_log("Missing {$hmacHeader} header");
        http_response_code(400);
        echo "Bad Request: Missing {$hmacHeader} header";
        exit;
    }
    
    // IMPORTANT: Read the raw request body
    $rawBody = file_get_contents('php://input');
    if ($rawBody === false) {
        error_log("Failed to read raw request body");
        http_response_code(500);
        echo 'Internal Server Error: Cannot read request body';
        exit;
    }
    
    try {
        $expectedSignature = hash_hmac('sha256', $rawBody, $webhookSecret, true); // true for raw binary output
        $expectedSignatureB64 = base64_encode($expectedSignature);
    
        // Use timing-safe comparison (hash_equals)
        if (!hash_equals($expectedSignatureB64, $receivedSignatureB64)) {
            error_log('Invalid signature');
            // Debugging (CAUTION in production):
            // error_log("Expected B64: " . $expectedSignatureB64);
            // error_log("Received B64: " . $receivedSignatureB64);
            http_response_code(401);
            echo 'Unauthorized: Invalid signature';
            exit;
        }
        error_log('Signature verified successfully'); // Use info level in proper logger
    
    } catch (\Exception $e) {
        error_log('Error during signature verification: ' . $e->getMessage());
        http_response_code(500);
        echo 'Internal Server Error during signature verification';
        exit;
    }
    
    // --- 2. Acknowledge Receipt Immediately (Before Parsing/Processing) ---
    // Send a 2xx Accepted response quickly.
    http_response_code(202);
    echo 'Accepted';
    
    // Flush output buffers to ensure the response is sent before potentially long processing
    if (function_exists('fastcgi_finish_request')) {
        // Good practice for PHP-FPM to release connection
        fastcgi_finish_request();
    } elseif ('cli' !== PHP_SAPI) {
        // Fallback for other SAPIs (might not work perfectly)
        ob_start(); // Start output buffering if not already started
        header('Connection: close');
        header('Content-Length: ' . ob_get_length());
        ob_end_flush();
        flush();
    }
    
    // --- 3. Parse and Process (Ideally Asynchronously) ---
    // WARNING: PHP typically processes requests synchronously. Long-running tasks here
    // can block new requests depending on the server setup.
    // For production, offload this processing to a background job queue (e.g., Redis Queue, Beanstalkd, RabbitMQ).
    
    try {
        $eventPayload = json_decode($rawBody, true, 512, JSON_THROW_ON_ERROR);
        $referenceId = $eventPayload['referenceId'] ?? 'N/A';
        $updatedAt = $eventPayload['updatedAt'] ?? 'N/A';
    
        error_log("Parsed payload for referenceId: {$referenceId}");
        // Careful logging full payload in production
        // error_log("Full payload: {$rawBody}");
    
        error_log("Processing event referenceId: {$referenceId}, UpdatedAt: {$updatedAt}");
    
        // --- Implement Idempotency Check Here ---
        // $alreadyProcessed = checkIfEventProcessed($referenceId, $updatedAt); // Implement this function
        // if ($alreadyProcessed) {
        //     error_log("Event referenceId {$referenceId} already processed or is older. Skipping.");
        //     exit; // Exit script cleanly
        // }
    
        // --- Your Business Logic Here ---
        // e.g., update your database based on eventPayload details...
        // Simulate work
        sleep(1); // Simulate work (DON'T DO THIS IN PRODUCTION REQUEST HANDLER)
        error_log("Business logic completed for referenceId: {$referenceId}");
    
    
        // --- Mark event as processed (for idempotency) ---
        // markEventAsProcessed($referenceId, $updatedAt); // Implement this function
        // error_log("Successfully marked referenceId {$referenceId} as processed.");
    
    
    } catch (\JsonException $e) {
        error_log('Failed to parse JSON payload after acknowledgment: ' . $e->getMessage());
        // Add monitoring/alerting here
        exit; // Stop processing if parsing fails
    } catch (\Throwable $e) { // Catch any other errors during processing
         error_log("Error during business logic/idempotency for referenceId {$referenceId}: {$e->getMessage()} " . $e->getTraceAsString());
         // Add monitoring/alerting. Event already acknowledged. May need manual reconciliation.
         exit;
    }
    
    error_log("Successfully processed event referenceId: {$referenceId} (end of script)"); // Should match logged success above
    
    // Helper function if not using Apache/Nginx specific ways
    if (!function_exists('getallheaders')) {
        function getallheaders(): array {
            $headers = [];
            foreach ($_SERVER as $name => $value) {
                if (str_starts_with($name, 'HTTP_')) {
                    $headerName = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', substr($name, 5)))));
                    $headers[$headerName] = $value;
                } elseif (in_array($name, ['CONTENT_TYPE', 'CONTENT_LENGTH'])) {
                     $headerName = str_replace(' ', '-', ucwords(strtolower(str_replace('_', ' ', $name))));
                     $headers[$headerName] = $value;
                }
            }
            return $headers;
        }
    }
    
    ?>