Overview
Henry’s Hosted Checkout is the fastest way to add commerce capabilities to your application. With our hosted checkout solution, you can accept payments without handling sensitive payment data or building complex UI components. Simply embed our checkout experience via iframe, webview, or redirect.
Perfect for : Startups and businesses that want to move fast and launch
quickly.
Why Choose Hosted Checkout?
Launch in Minutes Pre-built UI components and hosted pages get you live fast
Zero PCI Burden We handle all payment security and compliance requirements
Mobile Ready Responsive design works seamlessly across all devices
How It Works
Hosted Checkout uses a simple redirect or embedded iframe approach:
Quick Start
Get up and running in four simple steps:
Search Products
Find products from supported merchants: const response = await fetch ( 'https://api.sandbox.henrylabs.ai/v0/products/search' , {
method: 'POST' ,
headers: {
'x-api-key' : 'YOUR_API_KEY' ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
query: "running shoes" ,
limit: 20 ,
greaterThanPrice: 50 ,
lowerThanPrice: 200
})
});
const { data } = await response . json ();
// Display products to user
Initialize Cart
Add products to the cart using our simple API: const response = await fetch ( 'https://api.sandbox.henrylabs.ai/v0/cart/items' , {
method: 'POST' ,
headers: {
'x-api-key' : 'YOUR_API_KEY' ,
'x-user-id' : 'user_123' ,
'Content-Type' : 'application/json'
},
body: JSON . stringify ({
productsDetails: [{
productId: 'product_123' ,
name: 'Premium Sneakers' ,
price: '129.99' ,
quantity: 1 ,
productLink: 'https://store.com/sneakers' ,
productImageLink: 'https://image.url' ,
metadata: {
Size: '10' ,
Color: 'Black'
}
}]
})
});
Create Checkout Session
Initiate checkout to get the hosted checkout URL: const checkout = await fetch ( 'https://api.sandbox.henrylabs.ai/v0/cart/checkout' , {
method: 'POST' ,
headers: {
'x-api-key' : 'YOUR_API_KEY' ,
'x-user-id' : 'user_123'
}
});
const { data } = await checkout . json ();
const checkoutUrl = data . checkout_url ;
Redirect to Checkout
Send your user to the hosted checkout page: // Option 1: Full page redirect
window . location . href = checkoutUrl ;
// Option 2: Hosted iframe
const iframe = document . createElement ( 'iframe' );
iframe . src = checkoutUrl ;
iframe . style . width = '100%' ;
iframe . style . height = '600px' ;
document . getElementById ( 'checkout-container' ). appendChild ( iframe );
// Option 3: Modal popup
window . open ( checkoutUrl , 'checkout' , 'width=600,height=800' );
Preview Checkout Totals (Optional)
Use the session APIs to preview taxes and shipping before opening the hosted experience. Collect the buyer’s shipping details in your app, generate a quote, and read the normalized address if you want to display it back to the shopper.
const quoteRes = await fetch (
"https://api.sandbox.henrylabs.ai/v0/checkout/session/quote" ,
{
method: "POST" ,
headers: {
"x-api-key" : "YOUR_API_KEY" ,
"x-user-id" : "user_123" ,
"Content-Type" : "application/json"
},
body: JSON . stringify ({
shippingDetails: {
fullName: "Jamie Merchant" ,
email: "jamie@example.com" ,
phoneNumber: "+19175551234" ,
addressLine1: "350 5th Ave" ,
city: "New York" ,
stateOrProvince: "NY" ,
postalCode: "10118" ,
countryCode: "US"
}
})
}
);
const {
data : { session_token : sessionToken , order_metadata : orderMetadata }
} = await quoteRes . json ();
// Optional: show Henry-calculated totals before redirecting the buyer
console . log ( orderMetadata . total_price , orderMetadata . tax );
const shippingRes = await fetch (
"https://api.sandbox.henrylabs.ai/v0/checkout/session/shipping" ,
{
headers: {
"x-session-token" : sessionToken
}
}
);
const {
data : { shippingDetails , hasShipping }
} = await shippingRes . json ();
if ( hasShipping ) {
console . log ( "Validated shipping:" , shippingDetails );
}
Integration Methods
Method 1: Redirect
The simplest integration - redirect users to Henry’s hosted checkout:
function handleCheckout () {
// Create checkout session
const session = await createCheckoutSession ();
// Redirect to Henry
window . location . href = session . checkoutUrl ;
}
Method 2: Hosted Iframe
Keep users on your site with an embedded checkout:
< div id = "checkout-container" >
< iframe
id = "henry-checkout"
src = "{checkoutUrl}"
width = "100%"
height = "600"
frameborder = "0"
allow = "payment"
>
</ iframe >
</ div >
// Listen for checkout events
window . addEventListener ( "message" , ( event ) => {
// Verify the origin for security
if (
event . origin !== "https://checkout.henrylabs.ai" &&
event . origin !== "https://checkout.sandbox.henrylabs.ai"
)
return ;
if ( event . data ) {
const { status , action , orderId } = event . data ;
// Handle checkout events
switch ( action ) {
case "orderCompleted" :
console . log ( `Order ${ orderId } completed with status: ${ status } ` );
// Handle successful order
handleOrderSuccess ( orderId );
break ;
case "checkoutClosed" :
console . log ( `Checkout closed with status: ${ status } ` );
// Handle checkout modal close
handleCheckoutClosed ();
break ;
}
}
});
Balance between redirect and embedded:
function openCheckoutModal () {
const modal = window . open (
checkoutUrl ,
"henry-checkout" ,
"width=600,height=800,left=200,top=100" ,
);
// Listen for checkout events
window . addEventListener ( "message" , ( event ) => {
if (
event . origin !== "https://checkout.henrylabs.ai" &&
event . origin !== "https://checkout.sandbox.henrylabs.ai"
)
return ;
if ( event . data ) {
const { status , action , orderId } = event . data ;
if ( action === "orderCompleted" ) {
modal . close ();
handleOrderSuccess ( orderId );
} else if ( action === "checkoutClosed" ) {
modal . close ();
handleCheckoutCancelled ();
}
}
});
}
Event Handling
When using iframe or popup integration, Henry sends postMessage events to communicate checkout status:
Available Events
Implementation Example
// Track all checkout events
const eventLog = [];
window . addEventListener ( "message" , ( event ) => {
// Security: Verify the origin
if (
event . origin !== "https://checkout.henrylabs.ai" &&
event . origin !== "https://checkout.sandbox.henrylabs.ai"
)
return ;
if ( event . data ) {
const { status , action , orderId } = event . data ;
// Log all events from iframe
if ( action === "orderCompleted" || action === "checkoutClosed" ) {
const newEvent = {
action ,
orderId ,
status ,
timestamp: new Date (). toLocaleTimeString (),
};
eventLog . push ( newEvent );
console . log (
"ACTION:" ,
JSON . stringify ({
action ,
orderId ,
status ,
}),
);
// Handle specific events
if ( action === "orderCompleted" ) {
// Order successful - show confirmation
showOrderConfirmation ( orderId );
// Optionally close/hide the iframe
document . getElementById ( "henry-checkout" ). style . display = "none" ;
} else if ( action === "checkoutClosed" ) {
// User closed checkout - clean up UI
hideCheckoutModal ();
}
}
}
});
Always verify the event origin to prevent security vulnerabilities. Only
accept messages from Henry’s checkout domains: -
https://checkout.henrylabs.ai (production) -
https://checkout.sandbox.henrylabs.ai (sandbox)
Handling Results
Track order status after checkout:
// Check order status
function getOrderStatus ( orderId ) {
return fetch ( `https://api.sandbox.henrylabs.ai/v0/orders/ ${ orderId } ` , {
headers: { "x-api-key" : API_KEY },
}). then (( res ) => res . json ());
}
// Poll for updates
function pollOrderStatus ( orderId , callback ) {
const interval = setInterval ( async () => {
const order = await getOrderStatus ( orderId );
callback ( order . data );
if ([ "delivered" , "cancelled" , "failed" ]. includes ( order . data . status )) {
clearInterval ( interval );
}
}, 5000 );
return () => clearInterval ( interval );
}
Webhook support for real-time updates is coming soon.
Mobile Integration
Swift
import WebKit
class CheckoutViewController : UIViewController {
@IBOutlet weak var webView: WKWebView !
func loadCheckout ( url : String ) {
if let checkoutURL = URL ( string : url) {
webView. load ( URLRequest ( url : checkoutURL))
}
}
}
Kotlin
class CheckoutActivity : AppCompatActivity () {
private lateinit var webView: WebView
fun loadCheckout (url: String ) {
webView. loadUrl (url)
webView.settings.javaScriptEnabled = true
}
}
React Native
import { WebView } from "react-native-webview" ;
function CheckoutScreen ({ checkoutUrl }) {
return (
< WebView
source = { { uri: checkoutUrl } }
onMessage = { ( event ) => {
const data = JSON . parse ( event . nativeEvent . data );
if ( data . status === "complete" ) {
navigation . navigate ( "Success" );
}
} }
/>
);
}
Next Steps
Ready to implement Hosted Checkout?
Test Integration
Use test mode to validate your implementation
Go Live
Switch to production API key when ready
Hosted Checkout is the recommended starting point for most businesses. You can
always upgrade to Headless Checkout as your needs grow (requires Pro tier).