> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.paymentkit.com/guides/integration/sdk-reference/payment-kit-js/getting-started/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.paymentkit.com/_mcp/server.
# PaymentKit.js
PaymentKit.js is a lightweight JavaScript library that lets you securely collect payment information on your website. It renders payment inputs inside isolated iframes, ensuring sensitive card data never touches your servers and keeping you PCI compliant.
# Before you begin
To accept payments with PaymentKit.js, you'll need:
1. **A PaymentKit account** with at least one [payment processor connected](/guides/payment-orchestration)
2. **A backend server** to create checkout sessions and handle payment confirmation
3. **Your API keys** from the PaymentKit dashboard under **Developers > API Keys**
---
# Try it out
See PaymentKit.js in action with our demo application:
#### [Demo Repository](https://github.com/ProjectPayAdly/payment-kit-js-demo)
A complete working example showing card payments, PayPal, and Google Pay integration.
---
# Installation
Choose your preferred installation method:
#### CDN
Load PaymentKit.js directly from a CDN without any build step. Perfect for HTML-based projects or quick prototyping.
**unpkg (recommended):**
```html
```
**jsDelivr:**
```html
```
> **Info**
>
> The CDN bundle exposes a global `PaymentKit` object with all payment methods included (\~29 KB minified). Access payment methods via `PaymentKit.PaymentMethods.card`, `.paypal`, `.googlePay`, and `.applePay`.
#### NPM
```bash
npm install @payment-kit-js/vanilla
```
#### YARN
```bash
yarn add @payment-kit-js/vanilla
```
#### PNPM
```bash
pnpm add @payment-kit-js/vanilla
```
---
# How it works
Accepting a payment with PaymentKit.js involves three steps:
```mermaid
sequenceDiagram
participant Server as Your Server
participant PaymentKit as PaymentKit
participant Customer as Customer
Server->>PaymentKit: 1. Create checkout session
PaymentKit-->>Server: { secureToken }
Server->>Customer: 2. Initialize PaymentKit.js
Customer->>PaymentKit: 3. Customer enters payment details
PaymentKit-->>Server: Payment confirmed
```
1. **Create a checkout session** on your server to get a secure token
2. **Initialize PaymentKit.js** on your frontend with the token
3. **Collect and submit** payment details from your customer
---
# Step 1: Create a checkout session
Before collecting payment details, create a checkout session on your server. This generates a secure token that authorizes the frontend to process the payment.
```bash
curl -X POST https://app.paymentkit.com/api/{account_id}/checkout-sessions/ \
-H "Authorization: Bearer sk_test_..." \
-H "Content-Type: application/json" \
-d '{
"success_url": "https://yoursite.com/success",
"return_url": "https://yoursite.com/cancel",
"line_items": [
{
"price_id": "price_dev_x7k9m2n4",
"quantity": 1
}
]
}'
```
Replace `{account_id}` with your account's external ID (e.g., `acc_dev_abc123`).
The response includes a `secure_token` that you'll pass to PaymentKit.js:
```json
{
"id": "cs_dev_abc123",
"secure_token": "tok_abc123xyz789",
"state": "open",
"success_url": "https://yoursite.com/success",
"return_url": "https://yoursite.com/cancel",
"line_items": [
{
"price_id": "price_dev_x7k9m2n4",
"quantity": 1
}
]
}
```
---
# Step 2: Initialize PaymentKit
Import PaymentKit and the payment methods you want to support, then initialize with your configuration:
#### CDN
```html
```
> **Info**
>
> The CDN bundle includes all payment methods pre-loaded. Access them via `PaymentKit.PaymentMethods`.
#### NPM/ES Modules
```typescript
import PaymentKit from '@payment-kit-js/vanilla';
import CardPaymentMethod from '@payment-kit-js/vanilla/payment-methods/card';
const paymentKit = PaymentKit({
environment: 'production',
secureToken: 'aBcDeFgHiJkLmNoPqRsTuVwXyZ123456', // From your backend
paymentMethods: [CardPaymentMethod]
});
```
| Parameter | Description |
| ---------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `environment` | The environment to use: `'sandbox'` or `'production'`. Optional — defaults to `'production'` |
| `secureToken` | The `secure_token` from your checkout session |
| `paymentMethods` | Array of payment method handlers to enable |
| `cardTokenizationMode` | Optional. How card details are tokenized: `'vgs'` (card fields are collected in VGS Collect secure iframes) or `'direct'`. When omitted, PaymentKit reads the mode from your checkout session automatically |
| `vgsVaultId` | Optional. The VGS vault ID from your checkout session. Only used when `cardTokenizationMode` is `'vgs'` |
| `vgsEnvironment` | Optional. The VGS environment from your checkout session: `'sandbox'` or `'live'`. Only used when `cardTokenizationMode` is `'vgs'` |
> **Info**
>
> Use `'sandbox'` during development and testing. Switch to `'production'` when deploying to your live environment.
> **Info**
>
> You typically don't need to set `cardTokenizationMode`, `vgsVaultId`, or `vgsEnvironment`. When `cardTokenizationMode` is omitted, PaymentKit fetches your checkout session and configures all three automatically, falling back to `'direct'` if the session configuration can't be loaded. If you explicitly set `cardTokenizationMode: 'vgs'`, you must also provide `vgsVaultId` and `vgsEnvironment` — otherwise card fields fall back to `'direct'` mode.
---
# Step 3: Collect payment details
How you collect payment details depends on which payment method you're using. PaymentKit.js supports multiple payment methods that you can enable based on your needs.
## Available payment methods
#### Card payments
Accept credit and debit cards with PCI-compliant inputs and automatic 3D Secure handling.
#### PayPal
Let customers pay with their PayPal account using a popup-based authentication flow.
#### Google Pay
Accept Google Pay on supported devices for fast, secure checkout.
#### Apple Pay
Accept Apple Pay on Safari and iOS devices for fast, secure checkout.
## Using multiple payment methods
You can enable multiple payment methods in a single PaymentKit instance. This lets customers choose their preferred way to pay:
#### CDN
```html
```
#### NPM/ES Modules
```typescript
import PaymentKit from '@payment-kit-js/vanilla';
import CardPaymentMethod from '@payment-kit-js/vanilla/payment-methods/card';
import PayPalPaymentMethod from '@payment-kit-js/vanilla/payment-methods/paypal';
import GooglePayPaymentMethod from '@payment-kit-js/vanilla/payment-methods/google-pay';
import ApplePayPaymentMethod from '@payment-kit-js/vanilla/payment-methods/apple-pay';
const paymentKit = PaymentKit({
environment: 'production',
secureToken: 'aBcDeFgHiJkLmNoPqRsTuVwXyZ123456',
paymentMethods: [CardPaymentMethod, PayPalPaymentMethod, GooglePayPaymentMethod, ApplePayPaymentMethod]
});
// Now you can accept any of these payment methods
paymentKit.submit({
paymentMethod: 'card', // or 'paypal', 'google_pay', or 'apple_pay'
fields: { /* customer info */ },
onSuccess: (result) => { /* handle success */ },
onError: (errors) => { /* handle errors */ }
});
```
---
# Submitting a payment
Regardless of which payment method you use, payments are submitted using the `submit()` method. This method validates the payment details, processes the payment, and calls your success or error callbacks.
```typescript
paymentKit.submit({
fields: {
customer_name: 'Jane Smith',
customer_email: 'jane@example.com',
customer_country: 'US',
customer_zip_code: '94102'
},
paymentMethod: 'card',
onSuccess: (result) => {
console.log('Payment successful:', result.paymentIntentId);
// Redirect to success page or show confirmation
},
onError: (errors) => {
console.error('Payment failed:', errors);
// Display errors to the customer
}
});
```
## Customer fields
PaymentKit collects customer information to help with fraud prevention and compliance. All field values are passed as strings. The following fields are required for card payments:
| Field | Description |
| ------------------- | ----------------------------------------------------------------------------------------- |
| `customer_name` | Customer's full name (4-40 characters). Split on the first space into first and last name |
| `customer_email` | Customer's email address (validated for format) |
| `customer_country` | Two-letter country code (e.g., `US`, `GB`) |
| `customer_zip_code` | Postal or ZIP code |
### Optional billing fields
You can pass additional billing details. They are not validated by the SDK, and the billing address is attached to the payment whenever at least one address field (including `customer_country` or `customer_zip_code`) is provided:
| Field | Description |
| ------------------------ | ---------------------------------------------------------------- |
| `customer_business_name` | Customer's business or company name |
| `customer_address_line1` | Billing address line 1 |
| `customer_address_line2` | Billing address line 2 |
| `customer_city` | Billing address city |
| `customer_state` | Billing address state, province, or region |
| `customer_tax_ids` | Customer tax IDs, as a JSON-encoded array of strings (see below) |
Because all field values are strings, `customer_tax_ids` must be JSON-encoded:
```typescript
fields: {
// ...
customer_tax_ids: JSON.stringify(['EU123456789', 'GB987654321'])
}
```
Values that are not valid JSON, or that decode to an empty array, are silently ignored.
### Optional shipping fields
A shipping address is attached to the payment whenever at least one of these fields is provided:
| Field | Description |
| ------------------------ | ------------------------------------------- |
| `shipping_address_line1` | Shipping address line 1 |
| `shipping_address_line2` | Shipping address line 2 |
| `shipping_city` | Shipping address city |
| `shipping_state` | Shipping address state, province, or region |
| `shipping_zip_code` | Shipping postal or ZIP code |
| `shipping_country` | Shipping country code (e.g., `US`, `GB`) |
## Success response
When a payment succeeds, the `onSuccess` callback receives a result object:
```typescript
{
id: 'cca_dev_abc123',
checkoutAttemptId: 'ca_dev_abc123',
checkoutSessionId: 'cs_dev_xyz789',
paymentIntentId: 'pi_dev_def456',
state: 'checkout_succeeded'
}
```
---
# Handling errors
Payment errors are returned to the `onError` callback as an object with field-specific error codes:
```typescript
onError: (errors) => {
// Field validation errors
if (errors.customer_email === 'required') {
showFieldError('email', 'Email is required');
}
if (errors.customer_email === 'invalid') {
showFieldError('email', 'Please enter a valid email');
}
// Payment method errors
if (errors.card_pan) {
showFieldError('card', getCardErrorMessage(errors.card_pan));
}
// General errors
if (errors.root) {
showGeneralError(errors.root);
}
}
```
## Error types
### Form field errors
| Error field | Possible values | Description |
| ------------------- | --------------------- | --------------------------------------------------------- |
| `customer_name` | `required`, `invalid` | Customer name validation failed (must be 4-40 characters) |
| `customer_email` | `required`, `invalid` | Email validation failed |
| `customer_country` | `required`, `invalid` | Country code validation failed |
| `customer_zip_code` | `required`, `invalid` | ZIP code validation failed |
### Card input errors
| Error field | Possible values | Description |
| ----------- | -------------------------------------- | --------------------- |
| `card_pan` | `required`, `invalid`, `unknown_error` | Card number error |
| `card_exp` | `required`, `invalid`, `unknown_error` | Expiration date error |
| `card_cvc` | `required`, `invalid`, `unknown_error` | Security code error |
### Payment method errors
| Error field | Possible values | Description |
| ------------ | --------------- | ------------------------- |
| `paypal` | String message | PayPal-specific error |
| `google_pay` | String message | Google Pay-specific error |
| `apple_pay` | String message | Apple Pay-specific error |
| `root` | String message | General payment error |
---
# Cleaning up
When your checkout component unmounts or the user navigates away, always clean up PaymentKit resources to prevent memory leaks:
```typescript
// Call cleanup when done
paymentKit.cleanup();
```
In React, use a cleanup function in your effect:
```jsx
useEffect(() => {
const pk = PaymentKit({ /* config */ });
return () => {
pk.cleanup(); // Clean up on unmount
};
}, [secureToken]);
```
> **Warning**
>
> Failing to call `cleanup()` can leave orphaned iframes and event listeners, which may cause issues if the user returns to checkout.
---
# Content Security Policy
If your site uses a [Content-Security-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP) header, you must allowlist the following domains in your `script-src` directive for fraud prevention scripts to load:
| Environment | Domain | Notes |
| ------------------- | ----------------------------------- | --------------------------------------- |
| Production | `https://static.airwallex.com` | Airwallex card processors |
| Sandbox | `https://static-demo.airwallex.com` | Airwallex card processors |
| Production, Sandbox | `https://js.stripe.com` | Stripe processors (cards, 3DS, wallets) |
PaymentKit.js uses Stripe.js for Radar fraud signals, 3DS, and wallets. Load it on your page yourself; PaymentKit.js loads it for you only when PaymentKit has turned this on for your account.
**Example:**
```http
Content-Security-Policy: script-src 'self' https://static.airwallex.com https://js.stripe.com;
```
> **Info**
>
> If these domains are blocked, PaymentKit.js will log an error to the browser console with the specific domain that needs to be allowlisted.
> Accept payments directly on your website with secure, PCI-compliant payment elements powered by PaymentKit.js.