*** title: Card payments subtitle: 'Accept credit and debit cards with secure, PCI-compliant input elements.' ------------------------------------------------------------------------------------ PaymentKit.js renders card inputs inside isolated iframes, ensuring sensitive card data never touches your servers. # Setup ```html ``` ```typescript import PaymentKit from '@payment-kit-js/vanilla'; import CardPaymentMethod from '@payment-kit-js/vanilla/payment-methods/card'; const paymentKit = PaymentKit({ environment: 'sandbox', secureToken: 'aBcDeFgHiJkLmNoPqRsTuVwXyZ123456', // From your backend paymentMethods: [CardPaymentMethod] }); ``` # Create and mount card elements ```typescript // Create elements const cardNumber = paymentKit.card.createElement('card_pan'); const cardExpiry = paymentKit.card.createElement('card_exp'); const cardCvc = paymentKit.card.createElement('card_cvc'); // Mount to DOM containers cardNumber.mount('#card-number'); cardExpiry.mount('#card-expiry'); cardCvc.mount('#card-cvc'); ``` | Element | Type | Description | | ------------- | ---------- | -------------------------- | | Card number | `card_pan` | Card number (13-19 digits) | | Expiration | `card_exp` | MM / YY expiration date | | Security code | `card_cvc` | 3 or 4-digit CVC/CVV | # Element options Pass options to `createElement` to customize appearance and behavior: ```typescript const cardNumber = paymentKit.card.createElement('card_pan', { style: { fontSize: '16px', fontFamily: 'Inter, system-ui, sans-serif', color: '#1f2937' }, placeholder: '1234 1234 1234 1234', onLoaded: () => console.log('Ready'), onFocusChange: (isFocused) => console.log('Focus:', isFocused) }); ``` | Option | Type | Description | | --------------- | ------------------------------ | ----------------------------------------------------- | | `style` | `Record` | CSS properties applied to the input inside the iframe | | `placeholder` | `string` | Placeholder text for the input field | | `onLoaded` | `() => void` | Called when the input element is ready | | `onFocusChange` | `(isFocused: boolean) => void` | Called when the input gains or loses focus | ## Styling The `style` object applies CSS properties directly to the input element inside the iframe. For layout properties like height, border, and background, style the parent container in your HTML instead: ```html
``` PaymentKit.js automatically reads your container's padding and applies it to the input inside the iframe, so text alignment and vertical centering match your container's styling. # Submit payment ```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 ID:', result.paymentIntentId); window.location.href = '/success'; }, onError: (errors) => { // Card errors: errors.card_pan, errors.card_exp, errors.card_cvc // Form errors: errors.customer_name, errors.customer_email, etc. // General error: errors.root console.error(errors); } }); ``` # 3D Secure 3D Secure (3DS) authentication is handled automatically by PaymentKit.js when required by the card issuer or payment processor. When 3DS is required, PaymentKit.js displays a Stripe.js authentication modal. The customer completes authentication (entering a code or biometric), and PaymentKit.js verifies the result and completes the payment. No additional code is required in your `submit()` call. For 3DS to work, include Stripe.js in your page: `` # Error codes | Error code | Field | Description | | ------------------------ | ----- | --------------------------------------- | | `required` | All | Field is empty | | `invalid` | All | Basic validation failed | | `unknown_error` | All | Unexpected error during card processing | | `penpal_not_connected` | All | Card input iframe failed to connect | | `missing_checkout_token` | All | Checkout token missing from request |