Skip to main content

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:
1

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
2

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'
      }
    }]
  })
});
3

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;
4

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;
    }
  }
});

Method 3: Modal/Popup

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?
1

Get API Key

Onboard onto Henry to get started
2

Review Cart API

Explore the Cart endpoints for managing items
3

Test Integration

Use test mode to validate your implementation
4

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).