flintn-checkout 0.0.11 → 0.0.12

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.
package/README.md CHANGED
@@ -18,7 +18,7 @@ Full checkout UI rendered inside a single iframe. Includes card form, express pa
18
18
  import { useFlintNPayment } from 'flintn-checkout/react';
19
19
 
20
20
  function Checkout() {
21
- const { containerRef, isReady, paymentResult, error } = useFlintNPayment({
21
+ const { containerRef, isReady, paymentResult, attempts, error } = useFlintNPayment({
22
22
  config: {
23
23
  clientSessionId: 'your_client_session_id',
24
24
  },
@@ -29,6 +29,11 @@ function Checkout() {
29
29
  console.log('Payment failed:', result.error);
30
30
  }
31
31
  },
32
+ onEvent: (event) => {
33
+ // Per-attempt analytics — fires for every payment attempt outcome
34
+ // (initiated, soft/hard decline, 3DS, cancel, network error, success).
35
+ console.log('Attempt:', event.result, event.method, event.code);
36
+ },
32
37
  });
33
38
 
34
39
  return (
@@ -55,6 +60,9 @@ const payment = createFlintNPayment({
55
60
  console.log('Payment failed:', result.error);
56
61
  }
57
62
  },
63
+ onEvent: (event) => {
64
+ console.log('Attempt:', event.result, event.method);
65
+ },
58
66
  onReady: () => {
59
67
  console.log('Widget ready');
60
68
  },
@@ -88,6 +96,9 @@ payment.mount('#payment-container');
88
96
  onPayment: (result) => {
89
97
  console.log('Payment result:', result);
90
98
  },
99
+ onEvent: (event) => {
100
+ console.log('Attempt:', event);
101
+ },
91
102
  });
92
103
 
93
104
  payment.mount('#payment-container');
@@ -96,6 +107,92 @@ payment.mount('#payment-container');
96
107
  </html>
97
108
  ```
98
109
 
110
+ ## Events — terminal vs per-attempt
111
+
112
+ The SDK fires two streams of events. Use the one that fits your use case:
113
+
114
+ ### `onPayment` — terminal (session-final)
115
+
116
+ Fires **once** when the checkout session reaches a final state. Use this for redirecting, marking the order done, sending receipts, and conversion-failure analytics.
117
+
118
+ ```ts
119
+ onPayment(result: PaymentResult)
120
+ ```
121
+
122
+ Fires when:
123
+ - Payment succeeds → `status: 'PAYMENT_SUCCESS'`
124
+ - Session cannot continue (non-retryable decline, network error, SDK error, missing payment id, 3DS failure) → `status: 'PAYMENT_ERROR'`
125
+
126
+ **Does not fire** for soft declines, hard declines with a retryable session, or buyer cancellations — the buyer can still try another card or method.
127
+
128
+ ### `onEvent` — per-attempt analytics
129
+
130
+ Fires for **every payment attempt outcome**, including ones where the session continues. Use for funnel analytics, retry tracking, A/B test instrumentation, fraud signals.
131
+
132
+ ```ts
133
+ onEvent(event: PaymentAttempt)
134
+ ```
135
+
136
+ The `result` discriminator describes what happened at this step:
137
+
138
+ | `result` | When | Terminal `onPayment` follows? |
139
+ |---|---|---|
140
+ | `'INITIATED'` | Buyer clicked Pay / Apple Pay / PayPal and validation passed | — |
141
+ | `'THREE_DS_INITIATED'` | Authorize returned `THREE_DS_INITIATED`; 3DS challenge is opening | — |
142
+ | `'AUTHORIZED'` | Authorize succeeded | ✅ `PAYMENT_SUCCESS` |
143
+ | `'SOFT_DECLINE'` | Decline with `decline_type: SOFT_DECLINE` — buyer can retry | only if session is non-retryable |
144
+ | `'HARD_DECLINE'` | Decline with `decline_type: HARD_DECLINE` — card permanently bad | only if session is non-retryable |
145
+ | `'CANCELLED'` | Buyer dismissed Apple Pay sheet / closed PayPal popup / closed 3DS dialog | — |
146
+ | `'NETWORK_ERROR'` | Authorize HTTP failure, SDK crashed, missing token, unknown status | ✅ `PAYMENT_ERROR` |
147
+
148
+ A terminal `onPayment` event always fires *after* the corresponding `onEvent` for `AUTHORIZED` / `NETWORK_ERROR` / non-retryable declines / 3DS failures.
149
+
150
+ **Example funnel — soft decline → retry success:**
151
+
152
+ ```
153
+ onEvent → { result: 'INITIATED', method: 'PAYMENT_CARD' }
154
+ onEvent → { result: 'SOFT_DECLINE', method: 'PAYMENT_CARD', code: 'do_not_honor', message: 'Payment declined.' }
155
+ // buyer retries with another card
156
+ onEvent → { result: 'INITIATED', method: 'PAYMENT_CARD' }
157
+ onEvent → { result: 'AUTHORIZED', method: 'PAYMENT_CARD', paymentId: 'pay_...' }
158
+ onPayment → { status: 'PAYMENT_SUCCESS', data: 'pay_...' }
159
+ ```
160
+
161
+ **Example — Apple Pay buyer cancel (DEFAULT variant):**
162
+
163
+ ```
164
+ onEvent → { result: 'INITIATED', method: 'APPLE_PAY' }
165
+ onEvent → { result: 'CANCELLED', method: 'APPLE_PAY', message: 'Buyer dismissed Apple Pay' }
166
+ // no onPayment — session stays alive, buyer can pick another method
167
+ ```
168
+
169
+ **Example — PayPal popup → 3DS → success:**
170
+
171
+ ```
172
+ onEvent → { result: 'INITIATED', method: 'PAYPAL' }
173
+ onEvent → { result: 'THREE_DS_INITIATED', method: 'PAYPAL', paymentId: 'pay_...' }
174
+ onEvent → { result: 'AUTHORIZED', method: 'PAYPAL', paymentId: 'pay_...' }
175
+ onPayment → { status: 'PAYMENT_SUCCESS', data: 'pay_...' }
176
+ ```
177
+
178
+ ### `attempts` (React) — accumulated log
179
+
180
+ The `useFlintNPayment` hook also exposes `attempts: PaymentAttempt[]` — every event since mount, useful for rendering a per-attempt UI without wiring `onEvent` manually:
181
+
182
+ ```tsx
183
+ const { attempts } = useFlintNPayment({ ... });
184
+
185
+ return (
186
+ <ul>
187
+ {attempts.map((a, i) => (
188
+ <li key={i}>[{a.method}] {a.result} {a.code && `— ${a.code}`}</li>
189
+ ))}
190
+ </ul>
191
+ );
192
+ ```
193
+
194
+ The list resets when the checkout remounts (e.g. new `clientSessionId`).
195
+
99
196
  ## Container Sizing
100
197
 
101
198
  The widget auto-sizes to fit its content — you only need to set a width on the container. Height is managed by the SDK and updates automatically as the form changes state (loading, express view, card form, success).
@@ -111,7 +208,8 @@ Do **not** set a fixed `height` on the container — it will leave empty space b
111
208
  | Option | Type | Required | Default | Description |
112
209
  |--------|------|----------|---------|-------------|
113
210
  | `config` | `FlintNConfig` | Yes | — | Checkout configuration |
114
- | `onPayment` | `(result: PaymentResult) => void` | No | — | Payment result callback (success, error, cancelled) |
211
+ | `onPayment` | `(result: PaymentResult) => void` | No | — | Terminal session result (success / error) |
212
+ | `onEvent` | `(event: PaymentAttempt) => void` | No | — | Per-attempt analytics signal |
115
213
  | `onReady` | `() => void` | No | — | Widget loaded and ready |
116
214
  | `onError` | `(error: PaymentError) => void` | No | — | SDK initialization error |
117
215
  | `debug` | `boolean` | No | `false` | Enable console debug logs |
@@ -131,7 +229,8 @@ Do **not** set a fixed `height` on the container — it will leave empty space b
131
229
  |-------|------|-------------|
132
230
  | `containerRef` | `RefObject<HTMLDivElement>` | Ref to attach to container element |
133
231
  | `isReady` | `boolean` | Widget is loaded and ready |
134
- | `paymentResult` | `PaymentResult \| null` | Result after payment attempt |
232
+ | `paymentResult` | `PaymentResult \| null` | Result after terminal `onPayment` event |
233
+ | `attempts` | `PaymentAttempt[]` | Per-attempt event log (accumulated since mount) |
135
234
  | `error` | `PaymentError \| null` | SDK error if any |
136
235
 
137
236
  ---
@@ -142,6 +241,8 @@ Individual PCI-compliant input fields rendered as separate iframes. You control
142
241
 
143
242
  Each field (card number, expiry, CVV) is a separate iframe. Raw card data never touches your page.
144
243
 
244
+ > **Note:** Hosted Fields emits only the terminal `onPayment` event — there is no `onEvent` per-attempt stream. Use Iframe Checkout if you need granular attempt analytics.
245
+
145
246
  **React**
146
247
 
147
248
  ```tsx
@@ -378,6 +479,43 @@ interface PaymentError {
378
479
  }
379
480
  ```
380
481
 
482
+ ### PaymentAttempt
483
+
484
+ ```typescript
485
+ interface PaymentAttempt {
486
+ result:
487
+ | 'INITIATED'
488
+ | 'THREE_DS_INITIATED'
489
+ | 'AUTHORIZED'
490
+ | 'SOFT_DECLINE'
491
+ | 'HARD_DECLINE'
492
+ | 'CANCELLED'
493
+ | 'NETWORK_ERROR';
494
+ method:
495
+ | 'PAYMENT_CARD'
496
+ | 'GOOGLE_PAY'
497
+ | 'APPLE_PAY'
498
+ | 'PAYPAL'
499
+ | 'BANK_ACCOUNT'
500
+ | 'OTHER';
501
+ paymentId?: string; // Set when the backend has minted a payment id (auth response, 3DS, approve)
502
+ code?: string; // Processor decline code or internal error code (FNT-EC-*, FORBIDDEN, PAYPAL_ERROR, THREE_DS_FAILED, …)
503
+ message?: string; // Translated merchant-facing message for the code
504
+ }
505
+ ```
506
+
507
+ Const-object accessors are also exported if you prefer typed comparisons over string literals:
508
+
509
+ ```ts
510
+ import { AttemptResult, PaymentMethod } from 'flintn-checkout';
511
+
512
+ onEvent: (e) => {
513
+ if (e.result === AttemptResult.SOFT_DECLINE && e.method === PaymentMethod.PAYMENT_CARD) {
514
+ analytics.track('soft_decline_card', { code: e.code });
515
+ }
516
+ }
517
+ ```
518
+
381
519
  ### FieldState
382
520
  ```typescript
383
521
  interface FieldState {
@@ -472,6 +610,20 @@ The iframe checkout supports three layout variants via `formFields.formVariant`:
472
610
 
473
611
  LIST and RADIO automatically fall back to the DEFAULT layout when no express payment methods are available, since there's nothing to toggle between. The `cardButtonColor`, `cardButtonHoverColor`, and `cardButtonText` style overrides apply only to the LIST variant's "Credit or Debit Card" button.
474
612
 
613
+ ### Cancel-message behavior across variants
614
+
615
+ Express buttons (Apple Pay, PayPal) and the 3DS dialog can all be cancelled by the buyer. When that happens, an inline cancel message is shown in the card form **only when the card form is currently visible**:
616
+
617
+ | Variant | Apple Pay / PayPal cancel | 3DS dialog close |
618
+ |---|---|---|
619
+ | `DEFAULT` | Inline message shown | Inline message shown |
620
+ | `LIST` (EXPRESS view) | No inline message (form hidden) | No inline message |
621
+ | `LIST` (CARD view, after toggle) | Not reachable — cancel originates from EXPRESS view | Inline message shown |
622
+ | `RADIO` (EXPRESS active) | No inline message | No inline message |
623
+ | `RADIO` (CARD active) | Not reachable — cancel originates from EXPRESS view | Inline message shown |
624
+
625
+ Every cancellation still emits a `CANCELLED` `onEvent` regardless of variant, so analytics is unaffected.
626
+
475
627
  ## Supported Payment Methods
476
628
 
477
629
  ### Iframe Checkout
package/dist/index.d.mts CHANGED
@@ -1,6 +1,7 @@
1
1
  declare const EventType: {
2
2
  readonly WIDGET_READY: "WIDGET_READY";
3
3
  readonly WIDGET_CONFIG: "WIDGET_CONFIG";
4
+ readonly PAYMENT_ATTEMPT: "PAYMENT_ATTEMPT";
4
5
  readonly PAYMENT: "PAYMENT";
5
6
  readonly PAYMENT_SUCCESS: "PAYMENT_SUCCESS";
6
7
  readonly PAYMENT_ERROR: "PAYMENT_ERROR";
@@ -45,6 +46,32 @@ interface FlintNConfig {
45
46
  styles?: FormStyles;
46
47
  successRedirectUrl?: string;
47
48
  }
49
+ declare const PaymentMethod: {
50
+ readonly PAYMENT_CARD: "PAYMENT_CARD";
51
+ readonly GOOGLE_PAY: "GOOGLE_PAY";
52
+ readonly APPLE_PAY: "APPLE_PAY";
53
+ readonly PAYPAL: "PAYPAL";
54
+ readonly BANK_ACCOUNT: "BANK_ACCOUNT";
55
+ readonly OTHER: "OTHER";
56
+ };
57
+ type TPaymentMethod = (typeof PaymentMethod)[keyof typeof PaymentMethod];
58
+ declare const AttemptResult: {
59
+ readonly INITIATED: "INITIATED";
60
+ readonly THREE_DS_INITIATED: "THREE_DS_INITIATED";
61
+ readonly AUTHORIZED: "AUTHORIZED";
62
+ readonly SOFT_DECLINE: "SOFT_DECLINE";
63
+ readonly HARD_DECLINE: "HARD_DECLINE";
64
+ readonly CANCELLED: "CANCELLED";
65
+ readonly NETWORK_ERROR: "NETWORK_ERROR";
66
+ };
67
+ type TAttemptResult = (typeof AttemptResult)[keyof typeof AttemptResult];
68
+ interface PaymentAttempt {
69
+ result: TAttemptResult;
70
+ method: TPaymentMethod;
71
+ paymentId?: string;
72
+ code?: string;
73
+ message?: string;
74
+ }
48
75
  interface PaymentResult {
49
76
  status: 'PAYMENT_SUCCESS' | 'PAYMENT_ERROR' | 'PAYMENT_CANCELLED';
50
77
  data?: string;
@@ -61,6 +88,7 @@ interface FlintNPaymentOptions {
61
88
  origin?: string;
62
89
  config: FlintNConfig;
63
90
  onPayment?: (result: PaymentResult) => void;
91
+ onEvent?: (event: PaymentAttempt) => void;
64
92
  onReady?: () => void;
65
93
  onError?: (error: PaymentError) => void;
66
94
  debug?: boolean;
@@ -178,4 +206,4 @@ declare const validateConfig: (config: {
178
206
  }) => void;
179
207
  declare const sanitizeToken: (token: string) => string;
180
208
 
181
- export { CheckoutFormVariant, EventType, type FieldChangeEvent, FieldEventType, type FieldOptions, type FieldState, FieldType, type FieldValidationResult, type FieldsValidationResult, type FlintNConfig, type FlintNField, type FlintNFieldInternalCallbacks, type FlintNFields, type FlintNFieldsConfig, type FlintNFieldsOptions, type FlintNPayment, type FlintNPaymentOptions, type FormFields, type FormStyles, type PaymentError, type PaymentResult, type SubmitOptions, type TCheckoutFormVariant, type TEventType, type TFieldEventType, type TFieldType, buildIframeSrc, createFlintNField, createFlintNFields, createFlintNPayment, createIframeElement, parseOrigin, sanitizeToken, validateConfig };
209
+ export { AttemptResult, CheckoutFormVariant, EventType, type FieldChangeEvent, FieldEventType, type FieldOptions, type FieldState, FieldType, type FieldValidationResult, type FieldsValidationResult, type FlintNConfig, type FlintNField, type FlintNFieldInternalCallbacks, type FlintNFields, type FlintNFieldsConfig, type FlintNFieldsOptions, type FlintNPayment, type FlintNPaymentOptions, type FormFields, type FormStyles, type PaymentAttempt, type PaymentError, PaymentMethod, type PaymentResult, type SubmitOptions, type TAttemptResult, type TCheckoutFormVariant, type TEventType, type TFieldEventType, type TFieldType, type TPaymentMethod, buildIframeSrc, createFlintNField, createFlintNFields, createFlintNPayment, createIframeElement, parseOrigin, sanitizeToken, validateConfig };
package/dist/index.d.ts CHANGED
@@ -1,6 +1,7 @@
1
1
  declare const EventType: {
2
2
  readonly WIDGET_READY: "WIDGET_READY";
3
3
  readonly WIDGET_CONFIG: "WIDGET_CONFIG";
4
+ readonly PAYMENT_ATTEMPT: "PAYMENT_ATTEMPT";
4
5
  readonly PAYMENT: "PAYMENT";
5
6
  readonly PAYMENT_SUCCESS: "PAYMENT_SUCCESS";
6
7
  readonly PAYMENT_ERROR: "PAYMENT_ERROR";
@@ -45,6 +46,32 @@ interface FlintNConfig {
45
46
  styles?: FormStyles;
46
47
  successRedirectUrl?: string;
47
48
  }
49
+ declare const PaymentMethod: {
50
+ readonly PAYMENT_CARD: "PAYMENT_CARD";
51
+ readonly GOOGLE_PAY: "GOOGLE_PAY";
52
+ readonly APPLE_PAY: "APPLE_PAY";
53
+ readonly PAYPAL: "PAYPAL";
54
+ readonly BANK_ACCOUNT: "BANK_ACCOUNT";
55
+ readonly OTHER: "OTHER";
56
+ };
57
+ type TPaymentMethod = (typeof PaymentMethod)[keyof typeof PaymentMethod];
58
+ declare const AttemptResult: {
59
+ readonly INITIATED: "INITIATED";
60
+ readonly THREE_DS_INITIATED: "THREE_DS_INITIATED";
61
+ readonly AUTHORIZED: "AUTHORIZED";
62
+ readonly SOFT_DECLINE: "SOFT_DECLINE";
63
+ readonly HARD_DECLINE: "HARD_DECLINE";
64
+ readonly CANCELLED: "CANCELLED";
65
+ readonly NETWORK_ERROR: "NETWORK_ERROR";
66
+ };
67
+ type TAttemptResult = (typeof AttemptResult)[keyof typeof AttemptResult];
68
+ interface PaymentAttempt {
69
+ result: TAttemptResult;
70
+ method: TPaymentMethod;
71
+ paymentId?: string;
72
+ code?: string;
73
+ message?: string;
74
+ }
48
75
  interface PaymentResult {
49
76
  status: 'PAYMENT_SUCCESS' | 'PAYMENT_ERROR' | 'PAYMENT_CANCELLED';
50
77
  data?: string;
@@ -61,6 +88,7 @@ interface FlintNPaymentOptions {
61
88
  origin?: string;
62
89
  config: FlintNConfig;
63
90
  onPayment?: (result: PaymentResult) => void;
91
+ onEvent?: (event: PaymentAttempt) => void;
64
92
  onReady?: () => void;
65
93
  onError?: (error: PaymentError) => void;
66
94
  debug?: boolean;
@@ -178,4 +206,4 @@ declare const validateConfig: (config: {
178
206
  }) => void;
179
207
  declare const sanitizeToken: (token: string) => string;
180
208
 
181
- export { CheckoutFormVariant, EventType, type FieldChangeEvent, FieldEventType, type FieldOptions, type FieldState, FieldType, type FieldValidationResult, type FieldsValidationResult, type FlintNConfig, type FlintNField, type FlintNFieldInternalCallbacks, type FlintNFields, type FlintNFieldsConfig, type FlintNFieldsOptions, type FlintNPayment, type FlintNPaymentOptions, type FormFields, type FormStyles, type PaymentError, type PaymentResult, type SubmitOptions, type TCheckoutFormVariant, type TEventType, type TFieldEventType, type TFieldType, buildIframeSrc, createFlintNField, createFlintNFields, createFlintNPayment, createIframeElement, parseOrigin, sanitizeToken, validateConfig };
209
+ export { AttemptResult, CheckoutFormVariant, EventType, type FieldChangeEvent, FieldEventType, type FieldOptions, type FieldState, FieldType, type FieldValidationResult, type FieldsValidationResult, type FlintNConfig, type FlintNField, type FlintNFieldInternalCallbacks, type FlintNFields, type FlintNFieldsConfig, type FlintNFieldsOptions, type FlintNPayment, type FlintNPaymentOptions, type FormFields, type FormStyles, type PaymentAttempt, type PaymentError, PaymentMethod, type PaymentResult, type SubmitOptions, type TAttemptResult, type TCheckoutFormVariant, type TEventType, type TFieldEventType, type TFieldType, type TPaymentMethod, buildIframeSrc, createFlintNField, createFlintNFields, createFlintNPayment, createIframeElement, parseOrigin, sanitizeToken, validateConfig };
package/dist/index.js CHANGED
@@ -20,10 +20,12 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
20
20
  // src/index.ts
21
21
  var index_exports = {};
22
22
  __export(index_exports, {
23
+ AttemptResult: () => AttemptResult,
23
24
  CheckoutFormVariant: () => CheckoutFormVariant,
24
25
  EventType: () => EventType,
25
26
  FieldEventType: () => FieldEventType,
26
27
  FieldType: () => FieldType,
28
+ PaymentMethod: () => PaymentMethod,
27
29
  buildIframeSrc: () => buildIframeSrc,
28
30
  createFlintNField: () => createFlintNField,
29
31
  createFlintNFields: () => createFlintNFields,
@@ -39,6 +41,7 @@ module.exports = __toCommonJS(index_exports);
39
41
  var EventType = {
40
42
  WIDGET_READY: "WIDGET_READY",
41
43
  WIDGET_CONFIG: "WIDGET_CONFIG",
44
+ PAYMENT_ATTEMPT: "PAYMENT_ATTEMPT",
42
45
  PAYMENT: "PAYMENT",
43
46
  PAYMENT_SUCCESS: "PAYMENT_SUCCESS",
44
47
  PAYMENT_ERROR: "PAYMENT_ERROR",
@@ -51,6 +54,23 @@ var CheckoutFormVariant = {
51
54
  LIST: "LIST",
52
55
  RADIO: "RADIO"
53
56
  };
57
+ var PaymentMethod = {
58
+ PAYMENT_CARD: "PAYMENT_CARD",
59
+ GOOGLE_PAY: "GOOGLE_PAY",
60
+ APPLE_PAY: "APPLE_PAY",
61
+ PAYPAL: "PAYPAL",
62
+ BANK_ACCOUNT: "BANK_ACCOUNT",
63
+ OTHER: "OTHER"
64
+ };
65
+ var AttemptResult = {
66
+ INITIATED: "INITIATED",
67
+ THREE_DS_INITIATED: "THREE_DS_INITIATED",
68
+ AUTHORIZED: "AUTHORIZED",
69
+ SOFT_DECLINE: "SOFT_DECLINE",
70
+ HARD_DECLINE: "HARD_DECLINE",
71
+ CANCELLED: "CANCELLED",
72
+ NETWORK_ERROR: "NETWORK_ERROR"
73
+ };
54
74
  var FieldType = {
55
75
  CARD_NUMBER: "card-number",
56
76
  EXPIRY: "expiry",
@@ -183,6 +203,9 @@ function createFlintNPayment(options) {
183
203
  sendConfig();
184
204
  options.onReady?.();
185
205
  break;
206
+ case EventType.PAYMENT_ATTEMPT:
207
+ options.onEvent?.(payload);
208
+ break;
186
209
  case EventType.PAYMENT:
187
210
  options.onPayment?.(payload);
188
211
  break;
@@ -628,10 +651,12 @@ function createFlintNFields(options) {
628
651
  }
629
652
  // Annotate the CommonJS export names for ESM import in node:
630
653
  0 && (module.exports = {
654
+ AttemptResult,
631
655
  CheckoutFormVariant,
632
656
  EventType,
633
657
  FieldEventType,
634
658
  FieldType,
659
+ PaymentMethod,
635
660
  buildIframeSrc,
636
661
  createFlintNField,
637
662
  createFlintNFields,
package/dist/index.mjs CHANGED
@@ -2,6 +2,7 @@
2
2
  var EventType = {
3
3
  WIDGET_READY: "WIDGET_READY",
4
4
  WIDGET_CONFIG: "WIDGET_CONFIG",
5
+ PAYMENT_ATTEMPT: "PAYMENT_ATTEMPT",
5
6
  PAYMENT: "PAYMENT",
6
7
  PAYMENT_SUCCESS: "PAYMENT_SUCCESS",
7
8
  PAYMENT_ERROR: "PAYMENT_ERROR",
@@ -14,6 +15,23 @@ var CheckoutFormVariant = {
14
15
  LIST: "LIST",
15
16
  RADIO: "RADIO"
16
17
  };
18
+ var PaymentMethod = {
19
+ PAYMENT_CARD: "PAYMENT_CARD",
20
+ GOOGLE_PAY: "GOOGLE_PAY",
21
+ APPLE_PAY: "APPLE_PAY",
22
+ PAYPAL: "PAYPAL",
23
+ BANK_ACCOUNT: "BANK_ACCOUNT",
24
+ OTHER: "OTHER"
25
+ };
26
+ var AttemptResult = {
27
+ INITIATED: "INITIATED",
28
+ THREE_DS_INITIATED: "THREE_DS_INITIATED",
29
+ AUTHORIZED: "AUTHORIZED",
30
+ SOFT_DECLINE: "SOFT_DECLINE",
31
+ HARD_DECLINE: "HARD_DECLINE",
32
+ CANCELLED: "CANCELLED",
33
+ NETWORK_ERROR: "NETWORK_ERROR"
34
+ };
17
35
  var FieldType = {
18
36
  CARD_NUMBER: "card-number",
19
37
  EXPIRY: "expiry",
@@ -146,6 +164,9 @@ function createFlintNPayment(options) {
146
164
  sendConfig();
147
165
  options.onReady?.();
148
166
  break;
167
+ case EventType.PAYMENT_ATTEMPT:
168
+ options.onEvent?.(payload);
169
+ break;
149
170
  case EventType.PAYMENT:
150
171
  options.onPayment?.(payload);
151
172
  break;
@@ -590,10 +611,12 @@ function createFlintNFields(options) {
590
611
  return { createField, getField, validate, submit, unmount, getIsReady };
591
612
  }
592
613
  export {
614
+ AttemptResult,
593
615
  CheckoutFormVariant,
594
616
  EventType,
595
617
  FieldEventType,
596
618
  FieldType,
619
+ PaymentMethod,
597
620
  buildIframeSrc,
598
621
  createFlintNField,
599
622
  createFlintNFields,
package/dist/react.d.mts CHANGED
@@ -34,6 +34,32 @@ interface FlintNConfig {
34
34
  styles?: FormStyles;
35
35
  successRedirectUrl?: string;
36
36
  }
37
+ declare const PaymentMethod: {
38
+ readonly PAYMENT_CARD: "PAYMENT_CARD";
39
+ readonly GOOGLE_PAY: "GOOGLE_PAY";
40
+ readonly APPLE_PAY: "APPLE_PAY";
41
+ readonly PAYPAL: "PAYPAL";
42
+ readonly BANK_ACCOUNT: "BANK_ACCOUNT";
43
+ readonly OTHER: "OTHER";
44
+ };
45
+ type TPaymentMethod = (typeof PaymentMethod)[keyof typeof PaymentMethod];
46
+ declare const AttemptResult: {
47
+ readonly INITIATED: "INITIATED";
48
+ readonly THREE_DS_INITIATED: "THREE_DS_INITIATED";
49
+ readonly AUTHORIZED: "AUTHORIZED";
50
+ readonly SOFT_DECLINE: "SOFT_DECLINE";
51
+ readonly HARD_DECLINE: "HARD_DECLINE";
52
+ readonly CANCELLED: "CANCELLED";
53
+ readonly NETWORK_ERROR: "NETWORK_ERROR";
54
+ };
55
+ type TAttemptResult = (typeof AttemptResult)[keyof typeof AttemptResult];
56
+ interface PaymentAttempt {
57
+ result: TAttemptResult;
58
+ method: TPaymentMethod;
59
+ paymentId?: string;
60
+ code?: string;
61
+ message?: string;
62
+ }
37
63
  interface PaymentResult {
38
64
  status: 'PAYMENT_SUCCESS' | 'PAYMENT_ERROR' | 'PAYMENT_CANCELLED';
39
65
  data?: string;
@@ -50,6 +76,7 @@ interface FlintNPaymentOptions {
50
76
  origin?: string;
51
77
  config: FlintNConfig;
52
78
  onPayment?: (result: PaymentResult) => void;
79
+ onEvent?: (event: PaymentAttempt) => void;
53
80
  onReady?: () => void;
54
81
  onError?: (error: PaymentError) => void;
55
82
  debug?: boolean;
@@ -101,22 +128,13 @@ interface FlintNFieldsOptions {
101
128
  debug?: boolean;
102
129
  }
103
130
 
104
- /**
105
- * Options for the useFlintNPayment hook.
106
- *
107
- * Extends FlintNPaymentOptions but omits `onReady` and `onError` callbacks
108
- * as they are managed internally by the hook. Use the returned `isReady`
109
- * and `error` values instead.
110
- *
111
- * All other FlintNPaymentOptions fields (config, onPayment, debug)
112
- * can be passed directly.
113
- */
114
131
  interface UseFlintNPaymentOptions extends Omit<FlintNPaymentOptions, 'onReady' | 'onError'> {
115
132
  }
116
133
  interface UseFlintNPaymentReturn {
117
134
  containerRef: React.RefObject<HTMLDivElement | null>;
118
135
  isReady: boolean;
119
136
  paymentResult: PaymentResult | null;
137
+ attempts: Array<PaymentAttempt>;
120
138
  error: PaymentError | null;
121
139
  }
122
140
  declare function useFlintNPayment(options: UseFlintNPaymentOptions): UseFlintNPaymentReturn;
package/dist/react.d.ts CHANGED
@@ -34,6 +34,32 @@ interface FlintNConfig {
34
34
  styles?: FormStyles;
35
35
  successRedirectUrl?: string;
36
36
  }
37
+ declare const PaymentMethod: {
38
+ readonly PAYMENT_CARD: "PAYMENT_CARD";
39
+ readonly GOOGLE_PAY: "GOOGLE_PAY";
40
+ readonly APPLE_PAY: "APPLE_PAY";
41
+ readonly PAYPAL: "PAYPAL";
42
+ readonly BANK_ACCOUNT: "BANK_ACCOUNT";
43
+ readonly OTHER: "OTHER";
44
+ };
45
+ type TPaymentMethod = (typeof PaymentMethod)[keyof typeof PaymentMethod];
46
+ declare const AttemptResult: {
47
+ readonly INITIATED: "INITIATED";
48
+ readonly THREE_DS_INITIATED: "THREE_DS_INITIATED";
49
+ readonly AUTHORIZED: "AUTHORIZED";
50
+ readonly SOFT_DECLINE: "SOFT_DECLINE";
51
+ readonly HARD_DECLINE: "HARD_DECLINE";
52
+ readonly CANCELLED: "CANCELLED";
53
+ readonly NETWORK_ERROR: "NETWORK_ERROR";
54
+ };
55
+ type TAttemptResult = (typeof AttemptResult)[keyof typeof AttemptResult];
56
+ interface PaymentAttempt {
57
+ result: TAttemptResult;
58
+ method: TPaymentMethod;
59
+ paymentId?: string;
60
+ code?: string;
61
+ message?: string;
62
+ }
37
63
  interface PaymentResult {
38
64
  status: 'PAYMENT_SUCCESS' | 'PAYMENT_ERROR' | 'PAYMENT_CANCELLED';
39
65
  data?: string;
@@ -50,6 +76,7 @@ interface FlintNPaymentOptions {
50
76
  origin?: string;
51
77
  config: FlintNConfig;
52
78
  onPayment?: (result: PaymentResult) => void;
79
+ onEvent?: (event: PaymentAttempt) => void;
53
80
  onReady?: () => void;
54
81
  onError?: (error: PaymentError) => void;
55
82
  debug?: boolean;
@@ -101,22 +128,13 @@ interface FlintNFieldsOptions {
101
128
  debug?: boolean;
102
129
  }
103
130
 
104
- /**
105
- * Options for the useFlintNPayment hook.
106
- *
107
- * Extends FlintNPaymentOptions but omits `onReady` and `onError` callbacks
108
- * as they are managed internally by the hook. Use the returned `isReady`
109
- * and `error` values instead.
110
- *
111
- * All other FlintNPaymentOptions fields (config, onPayment, debug)
112
- * can be passed directly.
113
- */
114
131
  interface UseFlintNPaymentOptions extends Omit<FlintNPaymentOptions, 'onReady' | 'onError'> {
115
132
  }
116
133
  interface UseFlintNPaymentReturn {
117
134
  containerRef: React.RefObject<HTMLDivElement | null>;
118
135
  isReady: boolean;
119
136
  paymentResult: PaymentResult | null;
137
+ attempts: Array<PaymentAttempt>;
120
138
  error: PaymentError | null;
121
139
  }
122
140
  declare function useFlintNPayment(options: UseFlintNPaymentOptions): UseFlintNPaymentReturn;
package/dist/react.js CHANGED
@@ -32,6 +32,7 @@ var import_react = require("react");
32
32
  var EventType = {
33
33
  WIDGET_READY: "WIDGET_READY",
34
34
  WIDGET_CONFIG: "WIDGET_CONFIG",
35
+ PAYMENT_ATTEMPT: "PAYMENT_ATTEMPT",
35
36
  PAYMENT: "PAYMENT",
36
37
  PAYMENT_SUCCESS: "PAYMENT_SUCCESS",
37
38
  PAYMENT_ERROR: "PAYMENT_ERROR",
@@ -171,6 +172,9 @@ function createFlintNPayment(options) {
171
172
  sendConfig();
172
173
  options.onReady?.();
173
174
  break;
175
+ case EventType.PAYMENT_ATTEMPT:
176
+ options.onEvent?.(payload);
177
+ break;
174
178
  case EventType.PAYMENT:
175
179
  options.onPayment?.(payload);
176
180
  break;
@@ -226,18 +230,20 @@ function useFlintNPayment(options) {
226
230
  const containerRef = (0, import_react.useRef)(null);
227
231
  const paymentRef = (0, import_react.useRef)(null);
228
232
  const onPaymentRef = (0, import_react.useRef)(options.onPayment);
233
+ const onEventRef = (0, import_react.useRef)(options.onEvent);
229
234
  const [isReady, setIsReady] = (0, import_react.useState)(false);
230
- const [paymentResult, setPaymentResult] = (0, import_react.useState)(
231
- null
232
- );
235
+ const [paymentResult, setPaymentResult] = (0, import_react.useState)(null);
236
+ const [attempts, setAttempts] = (0, import_react.useState)([]);
233
237
  const [error, setError] = (0, import_react.useState)(null);
234
238
  (0, import_react.useEffect)(() => {
235
239
  onPaymentRef.current = options.onPayment;
236
- }, [options.onPayment]);
240
+ onEventRef.current = options.onEvent;
241
+ }, [options.onPayment, options.onEvent]);
237
242
  (0, import_react.useEffect)(() => {
238
243
  if (!containerRef.current) return;
239
244
  setIsReady(false);
240
245
  setPaymentResult(null);
246
+ setAttempts([]);
241
247
  setError(null);
242
248
  paymentRef.current = createFlintNPayment({
243
249
  ...options,
@@ -246,6 +252,10 @@ function useFlintNPayment(options) {
246
252
  setPaymentResult(result);
247
253
  onPaymentRef.current?.(result);
248
254
  },
255
+ onEvent: (event) => {
256
+ setAttempts((prev) => [...prev, event]);
257
+ onEventRef.current?.(event);
258
+ },
249
259
  onError: (err) => setError(err)
250
260
  });
251
261
  paymentRef.current.mount(containerRef.current);
@@ -265,6 +275,7 @@ function useFlintNPayment(options) {
265
275
  containerRef,
266
276
  isReady,
267
277
  paymentResult,
278
+ attempts,
268
279
  error
269
280
  };
270
281
  }
package/dist/react.mjs CHANGED
@@ -5,6 +5,7 @@ import { useEffect, useRef, useState } from "react";
5
5
  var EventType = {
6
6
  WIDGET_READY: "WIDGET_READY",
7
7
  WIDGET_CONFIG: "WIDGET_CONFIG",
8
+ PAYMENT_ATTEMPT: "PAYMENT_ATTEMPT",
8
9
  PAYMENT: "PAYMENT",
9
10
  PAYMENT_SUCCESS: "PAYMENT_SUCCESS",
10
11
  PAYMENT_ERROR: "PAYMENT_ERROR",
@@ -144,6 +145,9 @@ function createFlintNPayment(options) {
144
145
  sendConfig();
145
146
  options.onReady?.();
146
147
  break;
148
+ case EventType.PAYMENT_ATTEMPT:
149
+ options.onEvent?.(payload);
150
+ break;
147
151
  case EventType.PAYMENT:
148
152
  options.onPayment?.(payload);
149
153
  break;
@@ -199,18 +203,20 @@ function useFlintNPayment(options) {
199
203
  const containerRef = useRef(null);
200
204
  const paymentRef = useRef(null);
201
205
  const onPaymentRef = useRef(options.onPayment);
206
+ const onEventRef = useRef(options.onEvent);
202
207
  const [isReady, setIsReady] = useState(false);
203
- const [paymentResult, setPaymentResult] = useState(
204
- null
205
- );
208
+ const [paymentResult, setPaymentResult] = useState(null);
209
+ const [attempts, setAttempts] = useState([]);
206
210
  const [error, setError] = useState(null);
207
211
  useEffect(() => {
208
212
  onPaymentRef.current = options.onPayment;
209
- }, [options.onPayment]);
213
+ onEventRef.current = options.onEvent;
214
+ }, [options.onPayment, options.onEvent]);
210
215
  useEffect(() => {
211
216
  if (!containerRef.current) return;
212
217
  setIsReady(false);
213
218
  setPaymentResult(null);
219
+ setAttempts([]);
214
220
  setError(null);
215
221
  paymentRef.current = createFlintNPayment({
216
222
  ...options,
@@ -219,6 +225,10 @@ function useFlintNPayment(options) {
219
225
  setPaymentResult(result);
220
226
  onPaymentRef.current?.(result);
221
227
  },
228
+ onEvent: (event) => {
229
+ setAttempts((prev) => [...prev, event]);
230
+ onEventRef.current?.(event);
231
+ },
222
232
  onError: (err) => setError(err)
223
233
  });
224
234
  paymentRef.current.mount(containerRef.current);
@@ -238,6 +248,7 @@ function useFlintNPayment(options) {
238
248
  containerRef,
239
249
  isReady,
240
250
  paymentResult,
251
+ attempts,
241
252
  error
242
253
  };
243
254
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "flintn-checkout",
3
- "version": "0.0.11",
3
+ "version": "0.0.12",
4
4
  "description": "FlintN Payment SDK — drop-in iframe checkout for card payments and wallets with localization and theming.",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.mjs",