UNPKG

@payos-inc/payos-js

Version:

PayOS JavaScript SDK for browser-based checkout and wallet onboarding

516 lines (438 loc) 13.2 kB
# @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