@payos-inc/payos-js
Version:
PayOS JavaScript SDK for browser-based checkout and wallet onboarding
516 lines (438 loc) • 13.2 kB
Markdown
# @payos-inc/payos-js
JavaScript SDK for PayOS integration, providing checkout and wallet onboarding functionality.
## Installation
```bash
npm install @payos-inc/payos-js
```
CDN:
```html
<script src="https://unpkg.com/@payos-inc/payos-js@latest/dist/payos-js.min.js"></script>
```
## Quick Start
```javascript
import { PayOS } from '@payos-inc/payos-js';
const payos = new PayOS();
// Wallet Onboarding - Add payment methods
payos.walletOnboard.open({
token: 'YOUR_TOKEN', // Get from your backend
mode: 'popup', // or 'redirect'
environment: 'sandbox', // or 'production'
onComplete: (result) => {
console.log('Wallet User ID:', result.walletUserId);
console.log('Cards added:', result.linkedCardIds);
},
onError: (error) => {
console.error('Error:', error);
}
});
// Checkout - Process payments
payos.checkout.open({
token: 'YOUR_TOKEN', // Get from your backend
mode: 'popup', // or 'redirect'
environment: 'sandbox', // or 'production'
onComplete: (result) => {
console.log('Payment Intent ID:', result.paymentIntentId);
console.log('Auth completed:', result.authCompleted);
console.log('Credentials generated:', result.credentialsGenerated);
},
onError: (error) => {
console.error('Error:', error);
}
});
// Card Element - Embed secure card capture
const cardElement = PayOS.cardElement.init('#card-container', {
token: 'YOUR_TOKEN',
environment: 'sandbox',
styles: {
layout: { preset: 'two-row' },
base: { fontSize: '16px' }
},
onTokenized: (result) => {
console.log('Card tokenized:', result.card);
}
});
```
## API Reference
### Constructor
```javascript
const payos = new PayOS();
```
### Methods
#### `payos.walletOnboard.open(options)`
Opens the wallet onboarding flow to add payment methods.
#### `payos.walletOnboard.close()`
Closes the current wallet onboarding session.
#### `payos.walletOnboard.isActive()`
Returns `true` if wallet onboarding is currently active.
#### `payos.checkout.open(options)`
Opens the checkout flow to process payments.
#### `payos.checkout.close()`
Closes the current checkout session.
#### `payos.checkout.isActive()`
Returns `true` if checkout is currently active.
#### `payos.cardElement.init(container, options)`
Creates and mounts a secure card capture element in the specified container.
**Returns:** `CardElementInstance` with methods:
- `mount()` - Mount the element to DOM
- `unmount()` - Remove from DOM
- `destroy()` - Clean up completely
- `submit()` - Trigger form submission
- `configure(config)` - Update configuration
- `updateStyles(styles)` - Update styles dynamically
## Options
### Wallet Onboarding Options
| Option | Type | Required | Description |
|--------|------|----------|-------------|
| `token` | string | Yes | Session token from your backend |
| `mode` | string | No | 'popup' or 'redirect' (default: 'popup') |
| `environment` | string | No | 'sandbox' or 'production' (default: 'sandbox') |
| `merchantName` | string | No | Your merchant name to display |
| `returnUrl` | string | No | URL for redirect mode |
| `onComplete` | function | No | Called with `{walletUserId, linkedCardIds}` |
| `onError` | function | No | Called on error |
| `onCancel` | function | No | Called when user cancels |
| `onReady` | function | No | Called when UI is ready |
### Checkout Options
| Option | Type | Required | Description |
|--------|------|----------|-------------|
| `token` | string | Yes | Checkout token from your backend |
| `mode` | string | No | 'popup' or 'redirect' (default: 'popup') |
| `environment` | string | No | 'sandbox' or 'production' (default: 'sandbox') |
| `returnUrl` | string | No | URL for redirect mode |
| `onComplete` | function | No | Called when checkout completes |
| `onError` | function | No | Called on error |
| `onCancel` | function | No | Called when user cancels |
| `onReady` | function | No | Called when UI is ready |
### Card Element Options
| Option | Type | Required | Description |
|--------|------|----------|-------------|
| `token` | string | Yes | Session token from your backend |
| `environment` | string | No | 'sandbox' or 'production' (default: 'sandbox') |
| `styles` | object | No | Custom styles for the card fields (see Styling section) |
| `height` | string | No | Container height (default: '720px') |
| `onReady` | function | No | Called when card element is ready |
| `onTokenized` | function | No | Called with tokenized card data |
| `onChange` | function | No | Called when field validation changes |
| `onError` | function | No | Called on error |
| `onCancel` | function | No | Called when user cancels |
## Display Modes
### Popup Mode (Default)
Opens in a new window:
```javascript
payos.walletOnboard.open({
token: 'token',
mode: 'popup',
environment: 'sandbox'
});
```
### Redirect Mode
Redirects the current page:
```javascript
payos.walletOnboard.open({
token: 'token',
mode: 'redirect',
environment: 'sandbox',
returnUrl: 'https://yourapp.com/complete'
});
```
### Handling Redirect Returns
PayOS returns parameters prefixed with `payos_`:
```javascript
// In your return URL handler
const params = new URLSearchParams(window.location.search);
const status = params.get('payos_status'); // 'success', 'cancel', or 'error'
const encodedData = params.get('payos_data'); // URL-encoded JSON
const timestamp = params.get('payos_timestamp');
if (status === 'success' && encodedData) {
// Decode the data
const data = JSON.parse(decodeURIComponent(encodedData));
// For wallet onboarding:
if (data.walletUserId) {
console.log('Wallet User ID:', data.walletUserId);
console.log('Cards Added:', data.linkedCardIds);
}
// For checkout:
if (data.paymentIntentId) {
console.log('Payment Intent ID:', data.paymentIntentId);
console.log('Auth Completed:', data.authCompleted);
}
}
```
## Card Element
### Embedding Secure Card Capture
The Card Element provides a secure, PCI-compliant way to capture card details directly in your application. Card data never touches your servers - it's tokenized through secure iframes.
```javascript
// Basic setup
const cardElement = PayOS.cardElement.init('#card-container', {
token: 'YOUR_TOKEN',
environment: 'sandbox',
onTokenized: (result) => {
console.log('Card tokenized:', result.card);
// Submit to your backend
}
});
// With custom styling
const cardElement = PayOS.cardElement.init('#card-container', {
token: 'YOUR_TOKEN',
environment: 'sandbox',
styles: {
layout: {
preset: 'two-row', // Layout preset
showLabels: true, // Show field labels
gap: '16px' // Space between fields
},
base: {
fontSize: '16px',
color: '#333',
padding: '12px',
borderRadius: '8px',
border: '1px solid #ddd',
'&:focus': {
borderColor: '#007bff',
outline: 'none'
}
},
cardNumber: {
paddingRight: '50px' // Space for card icon
}
},
onTokenized: (result) => {
console.log('Card:', result.card);
console.log('Billing:', result.billingAddress);
}
});
```
### Card Element Styling
The Card Element supports extensive styling through the `styles` option:
#### Layout Styles
Controls the overall form layout:
```javascript
styles: {
layout: {
preset: 'two-row', // 'single-row' | 'two-row' | 'compact' | 'stacked'
showLabels: true, // Show/hide field labels
showErrorMessages: true, // Show validation errors
gap: '16px', // Space between fields
padding: '20px', // Container padding
backgroundColor: '#f5f5f5', // Background color
labels: {
cardNumber: 'Card Number', // Custom label text
expiry: 'Expiration', // or false to hide
cvv: 'Security Code'
}
}
}
```
**Layout Presets:**
- `two-row` (default): Card number on first row, expiry/CVV on second
- `single-row`: All fields in one horizontal row
- `compact`: Minimal spacing for tight layouts
- `stacked`: All fields vertically stacked (mobile-friendly)
#### Field Styles
Customize individual field appearance:
```javascript
styles: {
// Base styles apply to all fields
base: {
fontSize: '16px',
fontFamily: 'system-ui, sans-serif',
color: '#333',
padding: '12px',
height: '48px',
border: '1px solid #e0e0e0',
borderRadius: '8px',
backgroundColor: 'white',
'&:focus': {
borderColor: '#007bff',
boxShadow: '0 0 0 3px rgba(0,123,255,0.1)'
},
'&::placeholder': {
color: '#999'
}
},
// Override for specific fields
cardNumber: {
fontSize: '18px'
},
expiry: {
width: '140px'
},
cvc: {
width: '100px'
}
}
```
### Card Element Events
Handle card element events for better UX:
```javascript
const cardElement = PayOS.cardElement.init('#card-container', {
token: 'YOUR_TOKEN',
onReady: () => {
console.log('Card element ready');
// Enable submit button
},
onChange: (event) => {
console.log('Validation:', {
complete: event.complete, // All fields valid
empty: event.empty, // All fields empty
error: event.error // Validation error message
});
// Update UI based on validation
},
onTokenized: (result) => {
console.log('Success:', {
card: result.card, // Card details
billingAddress: result.billingAddress,
walletUserId: result.walletUserId
});
// Submit to your backend
},
onError: (error) => {
console.error('Error:', error);
// Show error to user
}
});
```
### Programmatic Control
Control the card element after initialization:
```javascript
// Submit the form programmatically
document.getElementById('submit-btn').onclick = () => {
cardElement.submit();
};
// Configure with user data
cardElement.configure({
walletUserId: 'user_123',
cardholderName: 'John Doe',
billingAddress: {
line1: '123 Main St',
city: 'San Francisco',
state: 'CA',
postalCode: '94105',
country: 'US'
}
});
// Update styles dynamically
cardElement.updateStyles({
base: {
fontSize: '18px',
color: '#000'
}
});
// Clean up
cardElement.unmount(); // Remove from DOM
cardElement.destroy(); // Complete cleanup
```
### Complete Example
```html
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/@payos-inc/payos-js@latest/dist/payos-js.min.js"></script>
</head>
<body>
<div id="card-element"></div>
<button id="pay-button">Pay</button>
<script>
const payos = new PayOS();
// Initialize card element
const cardElement = PayOS.cardElement.init('#card-element', {
token: 'YOUR_TOKEN_HERE',
environment: 'sandbox',
styles: {
layout: {
preset: 'two-row',
showLabels: true
},
base: {
fontSize: '16px',
padding: '12px',
borderRadius: '8px'
}
},
onChange: (event) => {
// Enable/disable pay button based on validation
document.getElementById('pay-button').disabled = !event.complete;
},
onTokenized: async (result) => {
// Send to your backend
const response = await fetch('/api/process-payment', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
cardId: result.card.id,
walletUserId: result.walletUserId
})
});
if (response.ok) {
alert('Payment successful!');
}
},
onError: (error) => {
alert('Error: ' + error.message);
}
});
// Handle pay button click
document.getElementById('pay-button').onclick = () => {
cardElement.submit();
};
</script>
</body>
</html>
```
## TypeScript
```typescript
import { PayOS, CardElementStyles, CardElementTokenizedEvent } from '@payos-inc/payos-js';
const payos = new PayOS();
// Wallet Onboarding with types
payos.walletOnboard.open({
token: 'token',
mode: 'popup',
environment: 'sandbox',
onComplete: (result) => {
// TypeScript support included
console.log(result.walletUserId); // string
console.log(result.linkedCardIds); // string[]
}
});
// Card Element with typed styles
const styles: CardElementStyles = {
layout: {
preset: 'two-row',
showLabels: true,
labels: {
cardNumber: 'Card Number',
expiry: 'Exp Date',
cvv: 'CVV'
}
},
base: {
fontSize: '16px',
color: '#333',
padding: '12px',
'&:focus': {
borderColor: '#007bff'
}
}
};
const cardElement = PayOS.cardElement.init('#card-container', {
token: 'token',
environment: 'sandbox',
styles,
onTokenized: (event: CardElementTokenizedEvent) => {
console.log(event.card?.id); // string | undefined
console.log(event.card?.last4); // string | undefined
console.log(event.walletUserId); // string | undefined
}
});
```
## Browser Support
- Chrome 89+
- Firefox 87+
- Safari 14+
- Edge 89+
## License
MIT
## Support
Contact: support@payos.ai
Documentation: https://docs.payos.ai