Skip to main content

Hosted Form Checkout

Introduction

The Hosted Form is a secure, PCI-DSS compliant payment form that can be embedded directly into your checkout page. It provides a simple integration path while maintaining a good balance between security and UI customization.

Features
  • Simple Integration: Minimal setup with pre-built form UI.
  • Secure Payment: PCI-compliant with all sensitive data handled by Purse.
  • Customizable: Control over labels, placeholders, and styling.
  • Multi-Payment Method: Supports various payment methods.

Prerequisites

Ensure you have:

  • Basic JavaScript, HTML, and CSS knowledge.
  • An active payment method configured.
  • A Purse API key.
  • A client session.

When to Use Hosted Form

Use the Hosted Form if:

  • You want a straightforward integration with minimal effort.
  • You need PCI compliance without complex iframe orchestration.
  • You want a consistent, branded payment experience with moderate customization.
  • You need to support multiple payment methods.
Need deeper customization?

For more granular control over individual input fields, consider using Hosted Fields instead.

Quick Start Guide

Step 1: Load the Headless Checkout SDK

Add the Headless Checkout SDK to your checkout page:

<script type="module">
import * as Purse from "https://cdn.purse-sandbox.com/headless-checkout/latest/purse.esm.js";
</script>

ℹ️ The SDK is served from Purse's CDN to meet PCI-DSS requirements. Do not self-host this file.

Step 2: Create Container Element

Add a container element where the hosted form will be rendered:

<div id="purse-hosted-form"></div>
<button id="pay-button">Pay Now</button>

Step 3: Initialize the Checkout

Use your client session data to create an instance of the checkout:

import * as Purse from "https://cdn.purse-sandbox.com/headless-checkout/latest/purse.esm.js";

// Initialize the checkout with your session data
const checkout = await Purse.createHeadlessCheckout(clientSession.widget.data);

API V1

import * as Purse from "https://cdn.purse-sandbox.com/headless-checkout/latest/purse.esm.js";

// Initialize the checkout with your session data
const checkout = await Purse.createHeadlessCheckout({
apiKey: "YOUR_API_KEY",
entityId: "YOUR_ENTITY_ID",
environment: "sandbox",
paymentSession: "YOUR_SESSION"
});

Step 4: Render the Hosted Form

Subscribe to available payment methods and render the Hosted Form:

// Subscribe to available payment methods
checkout.paymentMethods.subscribe((methods) => {
const creditCard = methods.find(m => m.method === "creditcard");

if (creditCard) {
// Render the Hosted Form
creditCard.getPaymentElement({
hostedForm: {
panInputLabel: "Card number",
panPlaceholder: "1234 5678 9012 3456",
cvvInputLabel: "Security code",
cvvPlaceholder: "123",
expirationInputLabel: "Expiration date",
expirationPlaceholder: "MM/YY",
holderInputLabel: "Cardholder name",
holderPlaceholder: "John Doe"
}
}).appendTo("purse-hosted-form");
}
});

💡 The appendTo() method mounts the hosted form to the specified container element.

Customization

The Hosted Form provides extensive customization options to match your brand and user experience requirements.

Labels and Placeholders

Customize field labels and placeholders using the hostedForm configuration:

creditCard.getPaymentElement({
hostedForm: {
panInputLabel: "Card number",
panPlaceholder: "1234 5678 9012 3456",
cvvInputLabel: "Security code",
cvvPlaceholder: "123",
expirationInputLabel: "Expiration date",
expirationPlaceholder: "MM/YY",
holderInputLabel: "Cardholder name",
holderPlaceholder: "John Doe"
}
}).appendTo("purse-hosted-form");

Theme Customization

Use the theme configuration to style the form elements:

creditCard.getPaymentElement({
hostedForm: {
panInputLabel: "Card number",
panPlaceholder: "1234 5678 9012 3456",
cvvInputLabel: "Security code",
cvvPlaceholder: "123",
expirationInputLabel: "Expiration date",
expirationPlaceholder: "MM/YY",
holderInputLabel: "Cardholder name",
holderPlaceholder: "John Doe"
},
theme: {
global: {
color: '#1f2933',
fontFamily: 'Arial, sans-serif',
fontSize: '16px',
gap: '8px'
},
input: {
padding: '12px',
borderRadius: '4px',
border: '1px solid #cbd5e0',
backgroundColor: '#ffffff',
':focus': {
borderColor: '#4299e1',
boxShadow: '0 0 0 3px rgba(66, 153, 225, 0.1)'
},
':invalid': {
borderColor: '#dc2626'
}
},
label: {
fontWeight: '500',
margin: '0 0 4px 0',
color: '#374151'
},
helperText: {
fontSize: '14px',
color: '#6b7280',
margin: '4px 0 0 0'
}
}
}).appendTo("purse-hosted-form");

Available Theme Properties

The theme object supports the following scopes:

  • global: Applies to the entire form (colors, fonts, spacing)
  • input: Styles for input fields (padding, borders, focus states)
  • label: Styles for field labels
  • helperText: Styles for helper/error messages
  • tooltip: Styles for tooltips

Each scope supports CSS properties and pseudo-selectors like :focus, :hover, :invalid, etc.

See Theme references to get the full list of available keys.

Custom Fonts

Contact Required

For compliance reasons, please contact us before using custom fonts. You need to provide the font file to the Purse team.

To use custom fonts, include the font URL in the global.fontSrc property:

theme: {
global: {
fontSrc: 'custom-font-file',
fontFamily: 'MyFont, sans-serif',
fontSize: '16px'
}
}

Handling Form Submission

Handle the form submission and call checkout.submitPayment():

const payButton = document.getElementById("pay-button");

payButton.addEventListener("click", async (e) => {
e.preventDefault();

payButton.disabled = true;
payButton.textContent = "Processing...";

try {
await checkout.submitPayment();
console.log("Payment successful!");
// Redirect or show success message
} catch (error) {
console.error("Payment failed:", error.message);
alert(error.message || "Payment failed");
} finally {
payButton.disabled = false;
payButton.textContent = "Pay Now";
}
});

Error Handling

Common Errors

Possible errors:

  • Expired session → Session has expired, create a new client session
  • Invalid configuration → Missing required configuration options
  • Payment method not supported → The payment method is not supported by Hosted Form
  • Technical errors → The payment method cannot be initialized

Complete Example

Here's a full working example:

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Hosted Form - Payment</title>
<style>
body {
font-family: system-ui, sans-serif;
max-width: 600px;
margin: 50px auto;
padding: 20px;
}
#purse-hosted-form {
margin-bottom: 20px;
}
button {
width: 100%;
padding: 12px;
background: #0066cc;
color: white;
border: none;
border-radius: 4px;
font-size: 16px;
cursor: pointer;
}
button:disabled {
opacity: 0.6;
cursor: not-allowed;
}
</style>
</head>
<body>
<h1>Payment Form</h1>

<div id="purse-hosted-form"></div>
<button id="pay-button">Pay Now</button>

<script type="module">
import * as Purse from "https://cdn.purse-sandbox.com/headless-checkout/latest/purse.esm.js";

// Initialize checkout with your session token
const checkout = await Purse.createHeadlessCheckout("client-session-token");

// Render the hosted form
checkout.paymentMethods.subscribe((methods) => {
const creditCard = methods.find(m => m.method === "creditcard");

if (creditCard) {
creditCard.getPaymentElement({
hostedForm: {
panInputLabel: "Card number",
panPlaceholder: "1234 5678 9012 3456",
cvvInputLabel: "Security code",
cvvPlaceholder: "123",
expirationInputLabel: "Expiration date",
expirationPlaceholder: "MM/YY",
holderInputLabel: "Cardholder name",
holderPlaceholder: "John Doe"
},
theme: {
global: {
color: '#1f2933',
fontFamily: 'Arial, sans-serif',
fontSize: '16px'
},
input: {
padding: '12px',
borderRadius: '4px',
border: '1px solid #cbd5e0',
':focus': {
borderColor: '#4299e1'
}
}
}
}).appendTo("purse-hosted-form");
}
});

// Handle form submission
document.getElementById("pay-button").addEventListener("click", async (e) => {
e.preventDefault();

const payButton = e.target;
payButton.disabled = true;
payButton.textContent = "Processing...";

try {
await checkout.submitPayment();
console.log("Payment successful!");
// Redirect or show success message
} catch (error) {
console.error("Payment failed:", error.message);
alert(error.message || "Payment failed");
} finally {
payButton.disabled = false;
payButton.textContent = "Pay Now";
}
});
</script>
</body>
</html>

Summary

The Hosted Form is ideal when you want:

  • Quick Integration: Simple setup with pre-built form UI
  • PCI Compliance: All sensitive data handled securely by Purse
  • Moderate Customization: Control over labels, placeholders, and styling
  • Multi-Payment Support: Works with various payment methods

For more granular control over individual fields, consider using Hosted Fields or the full Headless Checkout SDK.