LiquidCommerce Cloud SDK
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.
Table of Contents
Installation
Install the package with:
npm install @liquidcommerce/cloud-sdk
yarn add @liquidcommerce/cloud-sdk
pnpm add @liquidcommerce/cloud-sdk
Configuration
API Key Authentication
The LiquidCommerce API Key Authentication provides a secure method to obtain an access token for all other API calls to LiquidCommerce Services.
Example using LiquidCommerce client:
const client = await LiquidCommerce('YOUR_LIQUIDCOMMERCE_API_KEY', {
googlePlacesApiKey: 'YOUR_GOOGLE_PLACES_API_KEY',
env: LIQUID_COMMERCE_ENV.STAGE,
});
Click Here For Manual Authentication
Order API Authentication
LiquidCommerce provides a separate authentication mechanism for Order API endpoints. The Order client uses Basic Authentication with a username and password.
Example using LiquidCommerceOrders client:
const orderClient = await LiquidCommerceOrders({
userID: 'YOUR_ORDER_API_USER_ID',
password: 'YOUR_ORDER_API_PASSWORD',
env: LIQUID_COMMERCE_ENV.STAGE,
});
Click Here For Manual Authentication
Note: Order authentication credentials are required to access Order API. The SDK will return appropriate authentication errors if these credentials are missing or invalid.
Response Types
All API responses follow a consistent structure:
interface ApiResponse<T> {
statusCode: number;
message: string;
metadata: {
languages: string[];
timestamp: number;
timezone: string;
requestId: string;
path: string;
version: string;
};
data?: T;
}
Services and Usage
Auth
While the SDK handles authentication automatically, you can also manually retrieve the 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
Services for address validation and lookup:
const autocompleteResponse = await client.address.autocomplete({
input: '100 Madison Ave, New York',
});
const detailsResponse = await client.address.details({
id: 'ChIJd8BlQ2BZwokRjMKtTjMezRw',
});
Catalog
Product catalog search and availability services:
const availabilityResponse = await client.catalog.availability({
upcs: ['123456789012', '210987654321'],
grouping: ['group1', 'group2'],
ids: ['id1', 'id2'],
loc: {
address: {
one: '123 Main St',
city: 'New York',
state: 'NY',
zip: '10001',
},
},
shouldShowOffHours: true,
});
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 },
},
{
key: ENUM_FILTER_KEYS.AVAILABILITY,
values: ENUM_AVAILABILITY_VALUE.IN_STOCK,
},
],
loc: {
address: {
one: '123 Main St',
city: 'New York',
state: 'NY',
zip: '10001',
},
},
});
Cart
Shopping cart management:
const newCart = await client.cart.get();
const existingCart = await client.cart.get('cart_id', true);
const updatedCart = await client.cart.update({
id: 'cart_id',
items: [
{
partNumber: '123456789012_retailer_id',
quantity: 2,
fulfillmentId: 'fulfillment_id',
engravingLines: ['Line 1', 'Line 2'],
scheduledFor: '2024-12-25',
},
],
loc: {
address: {
one: '123 Main St',
city: 'New York',
state: 'NY',
zip: '10001',
},
},
promoCode: 'DISCOUNT10',
giftCards: ['GC123456'],
});
User
User profile and preferences management:
const userSession = await client.user.session({
email: 'user@example.com',
firstName: 'John',
lastName: 'Smith',
phone: '2125551234',
company: 'Company Inc',
profileImage: 'https://...',
birthDate: '1990-01-01',
id: 'user_id',
});
const userData = await client.user.fetch('user_id_or_email');
const newAddress = await client.user.addAddress({
userId: 'user_id',
placesId: 'google_places_id',
one: '100 Madison St',
two: 'Apt 4B',
city: 'New York',
state: 'NY',
zip: '10004',
country: 'US',
lat: 40.7128,
long: -74.006,
type: ENUM_ADDRESS_TYPE.SHIPPING,
isDefault: true,
});
const updatedAddress = await client.user.updateAddress({
});
const newPayment = await client.user.addPayment({
customerId: 'customer_id',
paymentMethodId: 'payment_method_id',
isDefault: true,
});
const updatedPayment = await client.user.updatePayment({
customerId: 'customer_id',
paymentMethodId: 'payment_method_id',
isDefault: true,
});
await client.user.purge('user_id_or_email');
await client.user.purgeAddress('address_id');
await client.user.purgePayment('customer_id', 'payment_id');
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.
const paymentSession = await client.user.paymentSession({
});
const { key, secret } = paymentSession.data.session;
Integration
-
Initialize and Mount
The LiquidCommercePaymentElement
function creates and manages the UI component.
const paymentElement = LiquidCommercePaymentElement({
session: {
key,
secret,
},
});
await paymentElement.mount({
elementId: 'payment-element-container',
appearance: {
theme: 'night',
},
elementOptions: {
layout: 'tabs',
},
});
-
Generate a Confirmation Token
Once the user has filled out the payment form, create a confirmation token. This token securely represents the payment details.
const result = await paymentElement.createConfirmationToken();
if (result.token) {
const confirmationToken = result.token;
} else {
console.error(result.message);
}
-
Confirm the Payment Session
Use the confirmation token to finalize the payment and retrieve the payment method details.
const confirmation = await client.user.confirmPaymentSession(confirmationToken);
if (confirmation.data) {
const paymentMethod = confirmation.data;
}
-
Lifecycle Management
Properly manage the element's lifecycle to ensure a smooth user experience and resource cleanup.
paymentElement.subscribe('ready', () => {
console.log('Payment element is ready.');
});
paymentElement.subscribe('change', (event) => {
});
paymentElement.unmount();
paymentElement.destroy();
Legacy Payment
The legacy payment system uses a previous version of our payment integration. For new integrations, we strongly recommend using the Payment Element for a more secure and flexible solution.
Prerequisites
const userSession = await client.user.session({
email: 'user@example.com',
});
const { setupIntent, publicKey } = userSession.data.session;
Payment Element Integration
await client.payment.mount({
clientSecret: userSession.data.session.setupIntent,
key: userSession.data.session.publicKey,
elementId: 'payment-element-container',
appearance: {
theme: 'night',
},
elementOptions: {
layout: 'tabs',
},
});
client.payment.subscribe('ready', () => {
});
client.payment.subscribe('change', (event) => {
const { complete, empty, value } = event;
});
const tokenResult = await client.payment.generateToken();
if ('error' in tokenResult) {
const { type, message, code } = tokenResult.error;
} else {
const { id, card } = tokenResult;
}
client.payment.unmount();
client.payment.destroy();
Security Considerations
-
PCI Compliance: The payment element handles card data securely within an iframe, ensuring your application never directly touches sensitive payment information.
-
Token-Based: All payment data is tokenized - you only receive secure tokens that can't be used to retrieve the original card details.
-
Single Use: Payment tokens are single-use and expire after a short time period.
-
Domain Validation: Payment elements will only work on domains that have been pre-registered with your account.
Best Practices
- Error Handling: Always implement proper error handling:
try {
const token = await client.payment.generateToken();
if ('error' in token) {
switch (token.error.type) {
case 'validation_error':
break;
case 'api_error':
break;
case 'client_error':
break;
case 'confirm_error':
break;
}
}
} catch (error) {
}
- 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
- Event Handling: Monitor element state for better user experience:
client.payment.subscribe('change', (event) => {
const { complete, empty } = event;
submitButton.disabled = !complete || empty;
});
client.payment.subscribe('loaderror', (event) => {
console.error('Payment element failed:', event.error);
});
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:
// 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
*/
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
- Use test credentials in staging environment
- Never use production credentials in development
- Test all error scenarios
- Verify proper cleanup implementation
- Test on multiple devices and browsers
Checkout
Checkout process management:
const preparedCheckout = await client.checkout.prepare({
cartId: 'cart_id',
customer: {
id: 'customer_id',
email: 'customer@example.com',
firstName: 'John',
lastName: 'Smith',
phone: '2125551234',
birthDate: '1990-01-01',
},
hasAgeVerify: true,
billingAddress: {
firstName: 'John',
lastName: 'Smith',
email: 'billing@example.com',
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: 'jane@example.com',
phone: '2125555678',
},
},
marketingPreferences: {
canEmail: true,
canSms: true,
},
deliveryTips: [
{
fulfillmentId: 'fulfillment_id',
tip: 500,
},
],
deliveryInstructions: [
{
fulfillmentId: 'fulfillment_id',
instructions: "",
},
],
acceptedAccountCreation: true,
scheduledDelivery: '2024-12-25T14:00:00Z',
promoCode: 'DISCOUNT10',
giftCards: ['GC123456'],
});
const completedCheckout = await client.checkout.complete({
token: preparedCheckout.token,
payment: 'payment_id',
});
Checkout Payment
For direct checkout payments, the flow is similar but uses the checkout session:
const preparedCheckout = await client.checkout.prepare({
cartId: 'cart_id',
});
const paymentElement = LiquidCommercePaymentElement({
session: {
key: preparedCheckout.data.payment.publicKey,
secret: preparedCheckout.data.payment.clientSecret,
}
});
await paymentElement.mount({
elementId: 'payment-element-container',
appearance: { theme: 'night' },
elementOptions: { layout: 'tabs' },
});
const result = await paymentElement.createConfirmationToken();
if (result.token) {
const confirmation = await client.user.confirmPaymentSession(confirmationToken);
if (confirmation?.data?.id) {
const completedCheckout = await client.checkout.complete({
token: preparedCheckout.data.token,
payment: confirmation?.data?.id,
});
}
}
paymentElement.unmount();
paymentElement.destroy();
Orders
Provides secure access to order data throughout the finalized states of the order lifecycle within the LiquidCommerce ecosystem.
const orderClient = await LiquidCommerceOrders({
userID: 'YOUR_ORDER_API_USER_ID',
password: 'YOUR_ORDER_API_PASSWORD',
env: LIQUID_COMMERCE_ENV.STAGE,
});
const orderResponse = await orderClient.order.fetch();
Click here to access the docs for the order response structure
Webhook
Webhook test services:
const webhookTestResult = await client.webhook.test();
Error Handling
The SDK throws errors for various scenarios. Always wrap SDK calls in try-catch blocks:
try {
const result = await client.someMethod();
} catch (error) {
console.error('Operation failed:', error.message);
}
Common error scenarios:
- Authentication failures
- Invalid parameters
- Network errors
- Resource not found
- Rate limiting
- Validation errors
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
Documentation
For more detailed information about each method and its parameters, please refer to our official documentation.