Overview
The Henry cart is a persistent server-side object that holds items from any merchant in a single checkout experience. Creating a cart immediately returns both a cartId and a checkoutUrl - there’s no separate step to generate a checkout link.
Prerequisites
import HenrySDK from '@henrylabs/sdk' ;
const henry = new HenrySDK ({
apiKey: process . env . HENRY_SDK_API_KEY ! ,
});
Create a cart
cart.create is the starting point. Pass an array of items using product link URLs (from search results or any product page), and optionally configure cart settings.
const cart = await henry . cart . create ({
items: [
{
link: 'https://www.nike.com/t/air-max-270-shoes/AH8050-002' ,
quantity: 1 ,
selectedOptions: [ 'regular' , 'black' , '10-w' ],
metadata: { source: 'homepage-recommendation' },
},
],
settings: {
options: {
allowPartialPurchase: true ,
},
commissionFeePercent: 5 ,
commissionFeeFixed: { value: 0.99 , currency: 'USD' },
},
tags: { userId: 'user_123' , region: 'us-ny' },
});
const { cartId , checkoutUrl } = cart . data ;
console . log ( 'Cart ID:' , cartId );
// → "crt_sa2aEsCz9PRM"
console . log ( 'Checkout URL:' , checkoutUrl );
// → "https://checkout.henrylabs.ai/cart/crt_sa2aEsCz9PRM"
The
checkoutUrl is your hosted checkout link - share it with your user directly. See
Checkout for how to embed it.
Cart creation response
{
success : boolean ;
status : string ;
message : string ;
data : {
cartId : string ; // e.g. "crt_sa2aEsCz9PRM" - store this
checkoutUrl : string ; // hosted checkout URL - ready to use immediately
data : {
items : CartItem [];
settings ?: CartSettings ;
};
metadata ?: Record < string , unknown > ;
};
}
Manage cart items
Add an item
Add a product to an existing cart. Use the product link URL as the identifier.
const updated = await henry . cart . item . add ( cartId , {
item: {
link: 'https://www.adidas.com/us/ultraboost-22-shoes/GX5591.html' ,
quantity: 1 ,
selectedOptions: [ 'regular' , 'core-black' , '9.5-w' ],
selectedShipping: { value: 'standard' },
coupons: [ 'SAVE10' ],
metadata: { giftWrap: true },
},
});
console . log ( updated . data . data . items . length ); // cart now has 2 items
Update an item quantity
const updated = await henry . cart . item . update ( cartId , {
item: {
link: 'https://www.nike.com/t/air-max-270-shoes/AH8050-002' ,
quantity: 3 , // set new quantity
},
});
Setting quantity to 0 via cart.item.update also removes the item from the cart.
Remove an item
const updated = await henry . cart . item . remove ( cartId , {
link: 'https://www.nike.com/t/air-max-270-shoes/AH8050-002' ,
});
console . log ( updated . data . data . items . length ); // one fewer item
Fetch carts
Henry exposes two retrieval methods with different shapes:
Method Returns Use when cart.list({ cartId?, tags? })Array of carts Looking up by tags, or paging through many carts cart.fetch(cartId, { buyer? })A single cart You know the cartId and optionally want to prefill checkout
List carts
// Fetch a specific cart by ID
const { data : carts } = await henry . cart . list ({ cartId });
const cart = carts [ 0 ];
console . log ( cart . data . items );
console . log ( cart . checkoutUrl ); // still valid - use it any time
// Filter carts by tags
const { data : userCarts } = await henry . cart . list ({
tags: { userId: 'user_123' },
});
Fetch a single cart (with optional buyer prefill)
cart.fetch returns one cart by id. Pass an optional buyer to prefill the hosted checkout - the returned checkoutUrl will embed the buyer details as query params so fields render pre-filled when the user opens it.
// Plain fetch by id
const { data : cart } = await henry . cart . fetch ( cartId );
console . log ( cart . data . items , cart . checkoutUrl );
// Fetch + prefill the hosted checkout
const { data : prefilled } = await henry . cart . fetch ( cartId , {
buyer: {
name: { firstName: 'Jane' , lastName: 'Doe' },
email: 'jane@example.com' ,
phone: '+15551234567' ,
shippingAddress: {
name: { firstName: 'Jane' , lastName: 'Doe' },
line1: '350 5th Ave' ,
city: 'New York' ,
province: 'NY' ,
postalCode: '10118' ,
countryCode: 'US' ,
},
},
});
// prefilled.checkoutUrl now renders with Jane's details pre-populated
buyer is purely a UX convenience for hosted checkout - it does not persist on the cart. To actually commit buyer info, use
Headless Checkout via
cart.checkout.purchase.
Delete a cart
Remove a cart entirely when it’s no longer needed (e.g. on session logout).
await henry . cart . delete ( cartId );
Cart item fields reference
Field Type Required Description linkstring✅ Direct product URL from any merchant quantitynumber- Defaults to 1 selectedOptionsstring[]- Ordered array of option values e.g. ['regular', 'black', '10-w'] selectedShipping{ id?, value? }- Preferred shipping method couponsstring[]- Coupon codes to apply at checkout metadataobject- Arbitrary key/value data passed through to orders
Attach key-value tags when creating a cart to associate it with your own identifiers (e.g. user IDs, regions, campaigns). You can then filter carts by tags with cart.list.
const cart = await henry . cart . create ({
items: [{ link: '...' , quantity: 1 }],
tags: { userId: 'user_123' , campaign: 'summer-sale' },
});
// Later, retrieve all carts for this user
const { data : carts } = await henry . cart . list ({
tags: { userId: 'user_123' },
});
Cart settings reference
Field Type Description options.allowPartialPurchasebooleanLet buyers remove items during checkout options.collectBuyerEmail"off" | "required" | "optional"Email collection behavior options.collectBuyerAddress"off" | "required" | "optional"Address collection behavior options.collectBuyerPhone"off" | "required" | "optional"Phone collection behavior commissionFeePercentnumberCommission as a percentage of the order total (0-100) commissionFeeFixed{ value, currency }Fixed commission amount added to the order eventsCartEvent[]Triggers to fire when cart events occur
Cart events
settings.events lets you attach triggers to cart lifecycle events. Each entry declares an event type to listen for, an optional conditional, and a list of actions (data) to fire when it occurs.
Supported event types
Order events
Event type Fires when orderAny order event order.purchaseAny purchase event (full or partial, any outcome) order.purchase.pendingPurchase created, awaiting payment confirmation order.purchase.processingPayment confirmed, placing with merchants order.purchase.completePurchase completed (full or partial) order.purchase.cancelledPurchase cancelled (full or partial) order.purchase.fullA full purchase resolves to any outcome order.purchase.full.pendingFull purchase pending payment confirmation order.purchase.full.processingFull purchase confirmed, placing with merchants order.purchase.full.completeAll items placed successfully order.purchase.full.cancelledFull purchase cancelled order.purchase.partialA partial purchase resolves to any outcome order.purchase.partial.pendingPartial purchase pending order.purchase.partial.processingPartial purchase processing order.purchase.partial.completePartial purchase completed order.purchase.partial.cancelledPartial purchase cancelled order.itemAny item-level event order.item.pendingIndividual item pending order.item.processingIndividual item processing order.item.completeIndividual item placed successfully order.item.failedIndividual item failed order.updateAny order update event order.update.3ds-required3DS authentication required order.update.adding-to-cartAdding item to merchant cart order.update.filling-address-detailsFilling in address details order.update.filling-card-detailsFilling in card details order.update.submitting-orderSubmitting the order order.update.changing-quantityChanging item quantity order.update.applying-couponApplying a coupon code order.update.selecting-shippingSelecting shipping option order.update.selecting-optionsSelecting product options
Points & tier events
Event type Fires when pointsAny points event points.givePoints awarded to a buyer points.removePoints removed from a buyer tierAny tier event tier.giveA tier assigned to a buyer tier.removeA tier removed from a buyer
Supported action types
Action type Description Required fields send_webhookPOST the event payload to a registered webhook webhookUUIDsend_emailSend a notification email - give_points_fixedAward a fixed number of points to the buyer pointsgive_points_per_spentAward points proportional to the order amount points, perAmountremove_points_fixedDeduct a fixed number of points from the buyer pointsremove_points_per_spentDeduct points proportional to the order amount points, perAmountgive_tierAssign a loyalty tier to the buyer tierUUIDremove_tierRemove the buyer’s current tier -
Example - webhook on successful purchase
const cart = await henry . cart . create ({
items: [
{
link: 'https://www.nike.com/t/air-max-270-shoes/AH8050-002' ,
quantity: 1 ,
},
],
settings: {
events: [
{
type: 'order.purchase.full.complete' ,
data: [
{
type: 'send_webhook' ,
webhookUUID: 'c5dbd16b-60f1-42c7-8d36-a55c46e7a8c6' ,
},
],
},
],
},
});
Example - award points on purchase
settings : {
events : [
{
type: 'order.purchase.full.complete' ,
data: [
{
type: 'give_points_per_spent' ,
points: 1 ,
perAmount: { value: 1 , currency: 'USD' }, // 1 point per $1 spent
},
],
},
],
}
Conditionals
Add a conditional to a trigger to gate it on the buyer’s current tier or points balance:
{
type : 'order.purchase.full.complete' ,
conditional : {
type : 'tier' ,
operator : 'equals' , // 'equals' | 'not_equals'
value : 'your-tier-uuid' ,
},
data : [{ type: 'give_points_fixed' , points: 500 }],
}
Register and manage webhooks in the Henry Dashboard . The webhookUUID is the identifier assigned when you create a webhook endpoint. See
Webhooks for payload shape, verification, and the full event reference.
Error handling
Error Cause 400 Bad RequestMissing required fields or invalid URL in link 401 UnauthorizedInvalid API key 404 Not FoundcartId does not exist or belongs to a different app
Next steps
Once your cart is ready, proceed to checkout:
Checkout Embed the hosted checkout or call the headless purchase API
Order Management Track and list orders after checkout completes