@payment-kit-js/vanilla 0.1.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/README.md +755 -0
  2. package/dist/cardsetupintent-D2gBMj3e.d.mts +35 -0
  3. package/dist/cardsetupintent-D2gBMj3e.d.mts.map +1 -0
  4. package/dist/connect-card-DO2EJxu6.mjs +19 -0
  5. package/dist/connect-card-DO2EJxu6.mjs.map +1 -0
  6. package/dist/connect-card-EaOlRbPS.d.mts +25 -0
  7. package/dist/connect-card-EaOlRbPS.d.mts.map +1 -0
  8. package/dist/connect-tunnel-x-BhVAej5Q.mjs +44 -0
  9. package/dist/connect-tunnel-x-BhVAej5Q.mjs.map +1 -0
  10. package/dist/connect-tunnel-x-Ce423Pa2.d.mts +92 -0
  11. package/dist/connect-tunnel-x-Ce423Pa2.d.mts.map +1 -0
  12. package/dist/index.d.mts +11 -0
  13. package/dist/index.d.mts.map +1 -0
  14. package/dist/index.mjs +69 -0
  15. package/dist/index.mjs.map +1 -0
  16. package/dist/next-action-handlers-DTsWjUIA.mjs +53 -0
  17. package/dist/next-action-handlers-DTsWjUIA.mjs.map +1 -0
  18. package/dist/payment-methods/card.d.mts +22 -0
  19. package/dist/payment-methods/card.d.mts.map +1 -0
  20. package/dist/payment-methods/card.mjs +183 -0
  21. package/dist/payment-methods/card.mjs.map +1 -0
  22. package/dist/payment-methods/google-pay.d.mts +49 -0
  23. package/dist/payment-methods/google-pay.d.mts.map +1 -0
  24. package/dist/payment-methods/google-pay.mjs +135 -0
  25. package/dist/payment-methods/google-pay.mjs.map +1 -0
  26. package/dist/payment-methods/next-action-handlers.d.mts +24 -0
  27. package/dist/payment-methods/next-action-handlers.d.mts.map +1 -0
  28. package/dist/payment-methods/next-action-handlers.mjs +3 -0
  29. package/dist/payment-methods/paypal.d.mts +49 -0
  30. package/dist/payment-methods/paypal.d.mts.map +1 -0
  31. package/dist/payment-methods/paypal.mjs +93 -0
  32. package/dist/payment-methods/paypal.mjs.map +1 -0
  33. package/dist/payment-methods/stripe-google-pay-adapter.d.mts +2 -0
  34. package/dist/payment-methods/stripe-google-pay-adapter.mjs +3 -0
  35. package/dist/penpal/connect-card.d.mts +4 -0
  36. package/dist/penpal/connect-card.mjs +4 -0
  37. package/dist/penpal/connect-tunnel-x.d.mts +3 -0
  38. package/dist/penpal/connect-tunnel-x.mjs +4 -0
  39. package/dist/penpal-BFKeZTVz.mjs +16 -0
  40. package/dist/penpal-BFKeZTVz.mjs.map +1 -0
  41. package/dist/publiccardcheckoutresponse-wxFCeVdO.d.mts +40 -0
  42. package/dist/publiccardcheckoutresponse-wxFCeVdO.d.mts.map +1 -0
  43. package/dist/stripe-google-pay-adapter-CkV5HWI-.d.mts +54 -0
  44. package/dist/stripe-google-pay-adapter-CkV5HWI-.d.mts.map +1 -0
  45. package/dist/stripe-google-pay-adapter-DMDArVp2.mjs +163 -0
  46. package/dist/stripe-google-pay-adapter-DMDArVp2.mjs.map +1 -0
  47. package/dist/types-6mOKdjCh.d.mts +64 -0
  48. package/dist/types-6mOKdjCh.d.mts.map +1 -0
  49. package/dist/utils-h0dxplHy.mjs +62 -0
  50. package/dist/utils-h0dxplHy.mjs.map +1 -0
  51. package/package.json +60 -0
package/README.md ADDED
@@ -0,0 +1,755 @@
1
+ # @payment-kit-js/vanilla
2
+
3
+ Vanilla JavaScript SDK for PaymentKit - A type-safe, framework-agnostic payment processing SDK supporting card payments, PayPal, and Google Pay.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @payment-kit-js/vanilla
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ```typescript
14
+ import PaymentKit from '@payment-kit-js/vanilla';
15
+ import CardPaymentMethod from '@payment-kit-js/vanilla/payment-methods/card';
16
+
17
+ // Initialize PaymentKit
18
+ const paymentKit = PaymentKit({
19
+ baseUrl: 'https://your-domain.com', // For loading iframes
20
+ apiBaseUrl: 'https://api.domain.com', // For API calls (optional, defaults to baseUrl)
21
+ secureToken: 'checkout_session_token', // From your backend
22
+ paymentMethods: [CardPaymentMethod]
23
+ });
24
+
25
+ // Mount card inputs
26
+ paymentKit.card.createElement('card_pan').mount('#card-number');
27
+ paymentKit.card.createElement('card_exp').mount('#card-expiry');
28
+ paymentKit.card.createElement('card_cvc').mount('#card-cvc');
29
+
30
+ // Submit payment
31
+ paymentKit.submit({
32
+ fields: {
33
+ customer_name: 'John Doe',
34
+ customer_email: 'john@example.com',
35
+ customer_country: 'US',
36
+ customer_zip_code: '10001'
37
+ },
38
+ paymentMethod: 'card',
39
+ onSuccess: (result) => console.log('Success:', result),
40
+ onError: (errors) => console.error('Error:', errors)
41
+ });
42
+
43
+ // Cleanup when done
44
+ paymentKit.cleanup();
45
+ ```
46
+
47
+ ## Payment Methods
48
+
49
+ ### Card Payments
50
+
51
+ Secure PCI-compliant card payments using isolated iframes.
52
+
53
+ #### Import
54
+
55
+ ```typescript
56
+ import CardPaymentMethod from '@payment-kit-js/vanilla/payment-methods/card';
57
+ import type { CardInputType } from '@payment-kit-js/vanilla/payment-methods/card';
58
+ ```
59
+
60
+ #### Initialize
61
+
62
+ ```typescript
63
+ const paymentKit = PaymentKit({
64
+ baseUrl: 'https://your-domain.com',
65
+ secureToken: 'checkout_token',
66
+ paymentMethods: [CardPaymentMethod]
67
+ });
68
+ ```
69
+
70
+ #### Create Card Elements
71
+
72
+ ```typescript
73
+ // Card input types: 'card_pan' | 'card_exp' | 'card_cvc'
74
+ const cardNumber = paymentKit.card.createElement('card_pan', {
75
+ style: {
76
+ height: '40px',
77
+ fontSize: '16px',
78
+ fontFamily: 'Arial, sans-serif',
79
+ color: '#32325d',
80
+ padding: '10px'
81
+ },
82
+ onLoaded: () => console.log('Card input loaded'),
83
+ onFocusChange: (isFocused) => console.log('Focus:', isFocused)
84
+ });
85
+
86
+ // Mount to DOM
87
+ const { unmount } = cardNumber.mount('#card-number-container');
88
+
89
+ // Unmount when needed
90
+ unmount();
91
+ ```
92
+
93
+ #### Submit Card Payment
94
+
95
+ ```typescript
96
+ paymentKit.submit({
97
+ fields: {
98
+ customer_name: 'John Doe',
99
+ customer_email: 'john@example.com',
100
+ customer_country: 'US',
101
+ customer_zip_code: '10001'
102
+ },
103
+ paymentMethod: 'card',
104
+ onSuccess: (result) => {
105
+ // result: { id, checkoutAttemptId, checkoutSessionId, paymentIntentId, state }
106
+ console.log('Payment successful:', result);
107
+ },
108
+ onError: (errors) => {
109
+ // errors.card_pan, errors.card_exp, errors.card_cvc
110
+ // errors.customer_name, errors.customer_email, etc.
111
+ console.error('Payment failed:', errors);
112
+ }
113
+ });
114
+ ```
115
+
116
+ #### 3D Secure (3DS) Support
117
+
118
+ Card payments automatically handle 3D Secure authentication:
119
+
120
+ 1. Submit payment
121
+ 2. If 3DS required, user is redirected to bank authentication page
122
+ 3. After authentication, payment completes automatically
123
+ 4. Success/error callback is triggered
124
+
125
+ No additional code needed - it's built-in!
126
+
127
+ ### PayPal
128
+
129
+ PayPal payments using popup-based authentication flow.
130
+
131
+ #### Import
132
+
133
+ ```typescript
134
+ import PayPalPaymentMethod from '@payment-kit-js/vanilla/payment-methods/paypal';
135
+ import type { PayPalSubmitOptions } from '@payment-kit-js/vanilla/payment-methods/paypal';
136
+ ```
137
+
138
+ #### Initialize
139
+
140
+ ```typescript
141
+ const paymentKit = PaymentKit({
142
+ baseUrl: 'https://your-domain.com',
143
+ apiBaseUrl: 'https://api.domain.com',
144
+ secureToken: 'checkout_token',
145
+ paymentMethods: [PayPalPaymentMethod]
146
+ });
147
+ ```
148
+
149
+ #### Submit PayPal Payment
150
+
151
+ ```typescript
152
+ paymentKit.submit({
153
+ fields: {
154
+ customer_name: 'John Doe',
155
+ customer_email: 'john@example.com',
156
+ customer_country: 'US',
157
+ customer_zip_code: '10001'
158
+ },
159
+ paymentMethod: 'paypal',
160
+ options: {
161
+ processorId: 'proc_xxx', // Your PayPal processor ID
162
+ customerInfo: {
163
+ first_name: 'John',
164
+ last_name: 'Doe'
165
+ }
166
+ },
167
+ onSuccess: (result) => {
168
+ console.log('PayPal payment approved:', result);
169
+ },
170
+ onError: (errors) => {
171
+ if (errors.paypal?.includes('popup')) {
172
+ alert('Please allow popups for PayPal payments');
173
+ }
174
+ console.error('PayPal error:', errors);
175
+ }
176
+ });
177
+ ```
178
+
179
+ **Important**: PayPal requires browser popups to be enabled. The SDK automatically:
180
+ - Opens PayPal authentication popup
181
+ - Polls for payment completion every 2 seconds
182
+ - Closes popup after completion
183
+ - Handles user cancellation
184
+
185
+ ### Google Pay
186
+
187
+ Google Pay payments using Stripe Payment Request API.
188
+
189
+ #### Import
190
+
191
+ ```typescript
192
+ import GooglePayPaymentMethod from '@payment-kit-js/vanilla/payment-methods/google-pay';
193
+ import type { GooglePaySubmitOptions } from '@payment-kit-js/vanilla/payment-methods/google-pay';
194
+ ```
195
+
196
+ #### Prerequisites
197
+
198
+ Add Stripe.js to your HTML:
199
+
200
+ ```html
201
+ <script src="https://js.stripe.com/v3/"></script>
202
+ ```
203
+
204
+ #### Initialize
205
+
206
+ ```typescript
207
+ const paymentKit = PaymentKit({
208
+ baseUrl: 'https://your-domain.com',
209
+ apiBaseUrl: 'https://api.domain.com',
210
+ secureToken: 'checkout_token',
211
+ paymentMethods: [GooglePayPaymentMethod]
212
+ });
213
+ ```
214
+
215
+ #### Submit Google Pay Payment
216
+
217
+ ```typescript
218
+ paymentKit.submit({
219
+ fields: {
220
+ customer_name: 'John Doe',
221
+ customer_email: 'john@example.com',
222
+ customer_country: 'US',
223
+ customer_zip_code: '10001'
224
+ },
225
+ paymentMethod: 'google_pay',
226
+ options: {
227
+ processorId: 'proc_xxx', // Your Google Pay processor ID
228
+ customerInfo: {
229
+ first_name: 'John',
230
+ last_name: 'Doe'
231
+ }
232
+ },
233
+ onSuccess: (result) => {
234
+ console.log('Google Pay success:', result);
235
+ },
236
+ onError: (errors) => {
237
+ if (errors.google_pay === 'Google Pay not available on this device') {
238
+ // Show alternative payment methods
239
+ }
240
+ console.error('Google Pay error:', errors);
241
+ }
242
+ });
243
+ ```
244
+
245
+ ## Multiple Payment Methods
246
+
247
+ Enable multiple payment methods in a single instance:
248
+
249
+ ```typescript
250
+ import CardPaymentMethod from '@payment-kit-js/vanilla/payment-methods/card';
251
+ import PayPalPaymentMethod from '@payment-kit-js/vanilla/payment-methods/paypal';
252
+ import GooglePayPaymentMethod from '@payment-kit-js/vanilla/payment-methods/google-pay';
253
+
254
+ const paymentKit = PaymentKit({
255
+ baseUrl: 'https://your-domain.com',
256
+ apiBaseUrl: 'https://api.domain.com',
257
+ secureToken: 'checkout_token',
258
+ paymentMethods: [CardPaymentMethod, PayPalPaymentMethod, GooglePayPaymentMethod]
259
+ });
260
+
261
+ // TypeScript knows all available methods
262
+ paymentKit.card.createElement('card_pan'); // ✓
263
+ paymentKit.submit({ paymentMethod: 'card', ... }); // ✓
264
+ paymentKit.submit({ paymentMethod: 'paypal', ... }); // ✓
265
+ paymentKit.submit({ paymentMethod: 'google_pay', ... }); // ✓
266
+ ```
267
+
268
+ ## API Reference
269
+
270
+ ### `PaymentKit(config)`
271
+
272
+ Initialize PaymentKit instance.
273
+
274
+ **Parameters**:
275
+
276
+ ```typescript
277
+ {
278
+ baseUrl: string; // URL for loading iframes (e.g., https://your-domain.com)
279
+ apiBaseUrl?: string; // URL for API calls (defaults to baseUrl)
280
+ secureToken: string; // Checkout session token from your backend
281
+ paymentMethods: PaymentMethod[]; // Array of payment method handlers
282
+ }
283
+ ```
284
+
285
+ **Returns**: Object with payment method APIs + `submit()` + `cleanup()`
286
+
287
+ ### `submit(options)`
288
+
289
+ Submit a payment using specified payment method.
290
+
291
+ **Parameters**:
292
+
293
+ ```typescript
294
+ {
295
+ fields: {
296
+ customer_name: string;
297
+ customer_email: string;
298
+ customer_country: string;
299
+ customer_zip_code: string;
300
+ };
301
+ paymentMethod: 'card' | 'paypal' | 'google_pay';
302
+ options?: unknown; // Payment method specific options
303
+ onSuccess: (result: { [key: string]: unknown }) => void;
304
+ onError: (errors: PaymentKitErrors) => void;
305
+ }
306
+ ```
307
+
308
+ ### `cleanup()`
309
+
310
+ Clean up all resources (iframes, popups, connections). **Always call this** when unmounting or leaving checkout.
311
+
312
+ ```typescript
313
+ useEffect(() => {
314
+ return () => {
315
+ paymentKit.cleanup();
316
+ };
317
+ }, [paymentKit]);
318
+ ```
319
+
320
+ ### Card API
321
+
322
+ #### `card.createElement(type, options)`
323
+
324
+ Create a secure card input iframe.
325
+
326
+ **Types**:
327
+ - `'card_pan'` - Card number
328
+ - `'card_exp'` - Expiration (MM/YY)
329
+ - `'card_cvc'` - Security code
330
+
331
+ **Options**:
332
+
333
+ ```typescript
334
+ {
335
+ style?: Record<string, string>; // CSS properties
336
+ onLoaded?: () => void;
337
+ onFocusChange?: (isFocused: boolean) => void;
338
+ }
339
+ ```
340
+
341
+ **Returns**: `{ mount: (selector: string) => { unmount: () => void } }`
342
+
343
+ ## Types
344
+
345
+ ### PaymentKitFields
346
+
347
+ ```typescript
348
+ type PaymentKitFields = {
349
+ customer_name: string;
350
+ customer_email: string;
351
+ customer_country: string;
352
+ customer_zip_code: string;
353
+ };
354
+ ```
355
+
356
+ ### PaymentKitErrors
357
+
358
+ ```typescript
359
+ type PaymentKitErrors = {
360
+ root?: string;
361
+
362
+ // Card errors
363
+ card_pan?: CardErrorCode;
364
+ card_exp?: CardErrorCode;
365
+ card_cvc?: CardErrorCode;
366
+
367
+ // PayPal errors
368
+ paypal?: string;
369
+
370
+ // Google Pay errors
371
+ google_pay?: string;
372
+
373
+ // Field validation
374
+ customer_name?: 'required' | 'invalid';
375
+ customer_email?: 'required' | 'invalid';
376
+ customer_country?: 'required' | 'invalid';
377
+ customer_zip_code?: 'required' | 'invalid';
378
+
379
+ // Processor
380
+ processor_id?: string;
381
+ };
382
+ ```
383
+
384
+ ### CardErrorCode
385
+
386
+ ```typescript
387
+ type CardErrorCode =
388
+ | 'required'
389
+ | 'invalid'
390
+ | 'incomplete'
391
+ | 'invalid_number'
392
+ | 'invalid_expiry'
393
+ | 'invalid_cvc';
394
+ ```
395
+
396
+ ## React Example
397
+
398
+ ### PaymentKit Provider
399
+
400
+ ```tsx
401
+ import { createContext, useContext, useEffect, useState } from 'react';
402
+ import PaymentKit from '@payment-kit-js/vanilla';
403
+ import CardPaymentMethod from '@payment-kit-js/vanilla/payment-methods/card';
404
+ import PayPalPaymentMethod from '@payment-kit-js/vanilla/payment-methods/paypal';
405
+ import GooglePayPaymentMethod from '@payment-kit-js/vanilla/payment-methods/google-pay';
406
+
407
+ type PaymentKitInstance = ReturnType<typeof PaymentKit<
408
+ [typeof CardPaymentMethod, typeof PayPalPaymentMethod, typeof GooglePayPaymentMethod]
409
+ >>;
410
+
411
+ const PaymentKitContext = createContext<PaymentKitInstance | null>(null);
412
+
413
+ export const usePaymentKit = () => {
414
+ const pk = useContext(PaymentKitContext);
415
+ if (!pk) throw new Error('PaymentKit not initialized');
416
+ return pk;
417
+ };
418
+
419
+ export const PaymentKitProvider = ({
420
+ children,
421
+ secureToken
422
+ }: {
423
+ children: React.ReactNode;
424
+ secureToken: string;
425
+ }) => {
426
+ const [paymentKit, setPaymentKit] = useState<PaymentKitInstance | null>(null);
427
+
428
+ useEffect(() => {
429
+ const pk = PaymentKit({
430
+ baseUrl: 'https://your-domain.com',
431
+ apiBaseUrl: 'https://api.domain.com',
432
+ secureToken,
433
+ paymentMethods: [CardPaymentMethod, PayPalPaymentMethod, GooglePayPaymentMethod]
434
+ });
435
+
436
+ setPaymentKit(pk);
437
+ return () => pk.cleanup();
438
+ }, [secureToken]);
439
+
440
+ if (!paymentKit) return null;
441
+
442
+ return (
443
+ <PaymentKitContext.Provider value={paymentKit}>
444
+ {children}
445
+ </PaymentKitContext.Provider>
446
+ );
447
+ };
448
+ ```
449
+
450
+ ### Card Input Component
451
+
452
+ ```tsx
453
+ import { useEffect } from 'react';
454
+ import { usePaymentKit } from './PaymentKitProvider';
455
+ import type { CardInputType } from '@payment-kit-js/vanilla/payment-methods/card';
456
+
457
+ export const CardInput = ({
458
+ type,
459
+ className
460
+ }: {
461
+ type: CardInputType;
462
+ className?: string;
463
+ }) => {
464
+ const paymentKit = usePaymentKit();
465
+
466
+ useEffect(() => {
467
+ const element = paymentKit.card.createElement(type, {
468
+ style: {
469
+ height: '42px',
470
+ fontSize: '16px',
471
+ padding: '10px',
472
+ border: '1px solid #e0e0e0',
473
+ borderRadius: '4px'
474
+ }
475
+ });
476
+
477
+ const { unmount } = element.mount(`#${type}`);
478
+ return unmount;
479
+ }, [type, paymentKit]);
480
+
481
+ return <div id={type} className={className} />;
482
+ };
483
+ ```
484
+
485
+ ### Payment Form
486
+
487
+ ```tsx
488
+ import { useState } from 'react';
489
+ import { usePaymentKit } from './PaymentKitProvider';
490
+ import { CardInput } from './CardInput';
491
+
492
+ export const PaymentForm = () => {
493
+ const paymentKit = usePaymentKit();
494
+ const [loading, setLoading] = useState(false);
495
+ const [values, setValues] = useState({
496
+ customer_name: '',
497
+ customer_email: '',
498
+ customer_country: '',
499
+ customer_zip_code: ''
500
+ });
501
+
502
+ const handleCardPayment = () => {
503
+ setLoading(true);
504
+ paymentKit.submit({
505
+ fields: values,
506
+ paymentMethod: 'card',
507
+ onSuccess: (result) => {
508
+ setLoading(false);
509
+ console.log('Success:', result);
510
+ },
511
+ onError: (errors) => {
512
+ setLoading(false);
513
+ console.error('Error:', errors);
514
+ }
515
+ });
516
+ };
517
+
518
+ const handlePayPalPayment = () => {
519
+ const [firstName, ...rest] = values.customer_name.split(' ');
520
+ setLoading(true);
521
+
522
+ paymentKit.submit({
523
+ fields: values,
524
+ paymentMethod: 'paypal',
525
+ options: {
526
+ processorId: 'proc_xxx',
527
+ customerInfo: {
528
+ first_name: firstName,
529
+ last_name: rest.join(' ')
530
+ }
531
+ },
532
+ onSuccess: (result) => {
533
+ setLoading(false);
534
+ console.log('PayPal success:', result);
535
+ },
536
+ onError: (errors) => {
537
+ setLoading(false);
538
+ console.error('PayPal error:', errors);
539
+ }
540
+ });
541
+ };
542
+
543
+ const handleGooglePayment = () => {
544
+ const [firstName, ...rest] = values.customer_name.split(' ');
545
+ setLoading(true);
546
+
547
+ paymentKit.submit({
548
+ fields: values,
549
+ paymentMethod: 'google_pay',
550
+ options: {
551
+ processorId: 'proc_xxx',
552
+ customerInfo: {
553
+ first_name: firstName,
554
+ last_name: rest.join(' ')
555
+ }
556
+ },
557
+ onSuccess: (result) => {
558
+ setLoading(false);
559
+ console.log('Google Pay success:', result);
560
+ },
561
+ onError: (errors) => {
562
+ setLoading(false);
563
+ console.error('Google Pay error:', errors);
564
+ }
565
+ });
566
+ };
567
+
568
+ return (
569
+ <form onSubmit={(e) => e.preventDefault()}>
570
+ <input
571
+ placeholder="Name"
572
+ value={values.customer_name}
573
+ onChange={(e) => setValues(prev => ({ ...prev, customer_name: e.target.value }))}
574
+ />
575
+ <input
576
+ placeholder="Email"
577
+ value={values.customer_email}
578
+ onChange={(e) => setValues(prev => ({ ...prev, customer_email: e.target.value }))}
579
+ />
580
+ <input
581
+ placeholder="Country"
582
+ value={values.customer_country}
583
+ onChange={(e) => setValues(prev => ({ ...prev, customer_country: e.target.value }))}
584
+ />
585
+ <input
586
+ placeholder="Zip Code"
587
+ value={values.customer_zip_code}
588
+ onChange={(e) => setValues(prev => ({ ...prev, customer_zip_code: e.target.value }))}
589
+ />
590
+
591
+ <h3>Card Payment</h3>
592
+ <CardInput type="card_pan" />
593
+ <CardInput type="card_exp" />
594
+ <CardInput type="card_cvc" />
595
+ <button onClick={handleCardPayment} disabled={loading}>
596
+ Pay with Card
597
+ </button>
598
+
599
+ <h3>Alternative Payments</h3>
600
+ <button onClick={handlePayPalPayment} disabled={loading}>
601
+ Pay with PayPal
602
+ </button>
603
+ <button onClick={handleGooglePayment} disabled={loading}>
604
+ Pay with Google Pay
605
+ </button>
606
+ </form>
607
+ );
608
+ };
609
+ ```
610
+
611
+ ## Error Handling
612
+
613
+ ### Validation Errors
614
+
615
+ ```typescript
616
+ paymentKit.submit({
617
+ fields: values,
618
+ paymentMethod: 'card',
619
+ onError: (errors) => {
620
+ if (errors.customer_email === 'required') {
621
+ showError('Email is required');
622
+ }
623
+ if (errors.card_pan === 'invalid_number') {
624
+ showError('Invalid card number');
625
+ }
626
+ },
627
+ onSuccess: () => { /* ... */ }
628
+ });
629
+ ```
630
+
631
+ ### Payment Method Specific Errors
632
+
633
+ ```typescript
634
+ // Card errors
635
+ onError: (errors) => {
636
+ if (errors.card_pan) console.error('Card number error');
637
+ if (errors.card_exp) console.error('Expiry error');
638
+ if (errors.card_cvc) console.error('CVC error');
639
+ }
640
+
641
+ // PayPal errors
642
+ onError: (errors) => {
643
+ if (errors.paypal?.includes('popup')) {
644
+ alert('Please enable popups');
645
+ }
646
+ if (errors.paypal?.includes('cancelled')) {
647
+ console.log('User cancelled PayPal');
648
+ }
649
+ }
650
+
651
+ // Google Pay errors
652
+ onError: (errors) => {
653
+ if (errors.google_pay === 'Google Pay not available on this device') {
654
+ // Hide Google Pay button
655
+ }
656
+ if (errors.google_pay?.includes('cancelled')) {
657
+ console.log('User cancelled Google Pay');
658
+ }
659
+ }
660
+ ```
661
+
662
+ ## Best Practices
663
+
664
+ ### 1. Always Cleanup
665
+
666
+ ```typescript
667
+ useEffect(() => {
668
+ const pk = PaymentKit({ /* config */ });
669
+ return () => pk.cleanup(); // Critical!
670
+ }, []);
671
+ ```
672
+
673
+ ### 2. Handle Loading States
674
+
675
+ ```typescript
676
+ const [loading, setLoading] = useState(false);
677
+
678
+ const handleSubmit = () => {
679
+ setLoading(true);
680
+ paymentKit.submit({
681
+ // ...
682
+ onSuccess: () => setLoading(false),
683
+ onError: () => setLoading(false)
684
+ });
685
+ };
686
+ ```
687
+
688
+ ### 3. Validate Before Submit
689
+
690
+ ```typescript
691
+ const handleSubmit = () => {
692
+ if (!values.customer_email || !values.customer_name) {
693
+ setError('Please fill required fields');
694
+ return;
695
+ }
696
+ paymentKit.submit({ /* ... */ });
697
+ };
698
+ ```
699
+
700
+ ### 4. Provide Fallback for Unsupported Methods
701
+
702
+ ```typescript
703
+ // Check Google Pay availability
704
+ paymentKit.submit({
705
+ paymentMethod: 'google_pay',
706
+ onError: (errors) => {
707
+ if (errors.google_pay?.includes('not available')) {
708
+ setShowGooglePay(false); // Hide button
709
+ }
710
+ }
711
+ });
712
+ ```
713
+
714
+ ### 5. Type Safety with TypeScript
715
+
716
+ ```typescript
717
+ // Type the instance based on enabled payment methods
718
+ type PaymentKitInstance = ReturnType<typeof PaymentKit<
719
+ [typeof CardPaymentMethod, typeof PayPalPaymentMethod]
720
+ >>;
721
+
722
+ // TypeScript enforces correct payment method names
723
+ paymentKit.submit({ paymentMethod: 'card' }); // ✓
724
+ paymentKit.submit({ paymentMethod: 'stripe' }); // ✗ Type error
725
+ ```
726
+
727
+ ## Troubleshooting
728
+
729
+ ### Card inputs not showing
730
+
731
+ - Ensure DOM elements exist before mounting
732
+ - Check `baseUrl` is accessible
733
+ - Verify `secureToken` is valid
734
+
735
+ ### PayPal popup blocked
736
+
737
+ - Instruct users to allow popups
738
+ - Check browser console for errors
739
+ - Verify `apiBaseUrl` is correct
740
+
741
+ ### Google Pay not available
742
+
743
+ - Add Stripe.js script tag
744
+ - Test on supported devices (Android Chrome, Safari on iOS)
745
+ - Check `processorId` is valid
746
+
747
+ ### TypeScript errors
748
+
749
+ - Ensure proper typing of PaymentKit instance
750
+ - Import types from correct paths
751
+ - Use `ReturnType<typeof PaymentKit<[...]>>` pattern
752
+
753
+ ## License
754
+
755
+ MIT