@paypercut/checkout-js 1.0.11 → 1.0.13
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 +352 -97
- package/dist/index.cjs +59 -10
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.ts +36 -4
- package/dist/index.mjs +59 -10
- package/dist/index.mjs.map +1 -1
- package/dist/paypercut-checkout.iife.min.js +1 -1
- package/dist/paypercut-checkout.iife.min.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -17,6 +17,8 @@ A lightweight, framework-agnostic JavaScript SDK for embedding Paypercut Checkou
|
|
|
17
17
|
- [Quick Start](#quick-start)
|
|
18
18
|
- [API Reference](#api-reference)
|
|
19
19
|
- [Events](#events)
|
|
20
|
+
- [Form Validation for Wallet Payments](#form-validation-for-wallet-payments)
|
|
21
|
+
- [Types](#types)
|
|
20
22
|
- [Usage Examples](#usage-examples)
|
|
21
23
|
- [Vanilla JavaScript](#vanilla-javascript-cdn)
|
|
22
24
|
- [TypeScript / ESM](#typescript--esm)
|
|
@@ -54,12 +56,12 @@ pnpm add @paypercut/checkout-js
|
|
|
54
56
|
|
|
55
57
|
```html
|
|
56
58
|
<!-- jsDelivr (recommended with SRI) -->
|
|
57
|
-
<script src="https://cdn.jsdelivr.net/npm/@paypercut/checkout-js@1.0.
|
|
59
|
+
<script src="https://cdn.jsdelivr.net/npm/@paypercut/checkout-js@1.0.13/dist/paypercut-checkout.iife.min.js"
|
|
58
60
|
integrity="sha384-..."
|
|
59
61
|
crossorigin="anonymous"></script>
|
|
60
62
|
|
|
61
63
|
<!-- or UNPKG -->
|
|
62
|
-
<script src="https://unpkg.com/@paypercut/checkout-js@1.0.
|
|
64
|
+
<script src="https://unpkg.com/@paypercut/checkout-js@1.0.13/dist/paypercut-checkout.iife.min.js"></script>
|
|
63
65
|
```
|
|
64
66
|
|
|
65
67
|
---
|
|
@@ -118,12 +120,19 @@ Creates a new checkout instance.
|
|
|
118
120
|
|
|
119
121
|
#### Options
|
|
120
122
|
|
|
121
|
-
| Option
|
|
122
|
-
|
|
123
|
-
| `id`
|
|
124
|
-
| `containerId`
|
|
123
|
+
| Option | Type | Required | Default | Description |
|
|
124
|
+
|------------------|------|----------|---------|-------------|
|
|
125
|
+
| `id` | `string` | Yes | — | Checkout session identifier (e.g., `CHK_12345`) |
|
|
126
|
+
| `containerId` | `string \| HTMLElement` | Yes | — | CSS selector or element where iframe mounts |
|
|
127
|
+
| `locale` | `string` | No | `'auto'` | Locale for checkout UI. Options: `'auto'`, `'en'`, `'en-GB'`, `'bg'`, `'bg-BG'` |
|
|
128
|
+
| `lang` | `string` | No | `'auto'` | Locale for checkout UI. Options: `'auto'`, `'en'`, `'en-GB'`, `'bg'`, `'bg-BG'` |
|
|
129
|
+
| `ui_mode` | `'hosted' \| 'embedded'` | No | `'embedded'` | UI mode for checkout display |
|
|
130
|
+
| `wallet_options` | `string[]` | No | `['apple_pay', 'google_pay']` | Digital wallet options. Pass `[]` to disable all wallets |
|
|
131
|
+
| `form_only` | `boolean` | No | `false` | Show only payment form (no Pay Now button - use external button with `submit()`) |
|
|
125
132
|
|
|
126
|
-
####
|
|
133
|
+
#### Examples
|
|
134
|
+
|
|
135
|
+
**Basic initialization:**
|
|
127
136
|
|
|
128
137
|
```typescript
|
|
129
138
|
const checkout = PaypercutCheckout({
|
|
@@ -132,6 +141,55 @@ const checkout = PaypercutCheckout({
|
|
|
132
141
|
});
|
|
133
142
|
```
|
|
134
143
|
|
|
144
|
+
**With all options:**
|
|
145
|
+
|
|
146
|
+
```typescript
|
|
147
|
+
const checkout = PaypercutCheckout({
|
|
148
|
+
id: 'CHK_12345',
|
|
149
|
+
containerId: '#checkout-container',
|
|
150
|
+
locale: 'en', // 'auto' | 'en' | 'en-GB' | 'bg' | 'bg-BG'
|
|
151
|
+
lang: 'en', // 'auto' | 'en' | 'en-GB' | 'bg' | 'bg-BG'
|
|
152
|
+
ui_mode: 'embedded', // 'hosted' | 'embedded'
|
|
153
|
+
wallet_options: ['apple_pay', 'google_pay'], // Can be empty array [] or contain one/both options
|
|
154
|
+
form_only: false // Set true to hide Pay Now button (use external button)
|
|
155
|
+
});
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
**Disable wallet payments:**
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
const checkout = PaypercutCheckout({
|
|
162
|
+
id: 'CHK_12345',
|
|
163
|
+
containerId: '#checkout-container',
|
|
164
|
+
wallet_options: [] // No Apple Pay or Google Pay buttons
|
|
165
|
+
});
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
**Only Apple Pay:**
|
|
169
|
+
|
|
170
|
+
```typescript
|
|
171
|
+
const checkout = PaypercutCheckout({
|
|
172
|
+
id: 'CHK_12345',
|
|
173
|
+
containerId: '#checkout-container',
|
|
174
|
+
wallet_options: ['apple_pay'] // Only Apple Pay, no Google Pay
|
|
175
|
+
});
|
|
176
|
+
```
|
|
177
|
+
|
|
178
|
+
**Form-only mode (external submit button):**
|
|
179
|
+
|
|
180
|
+
```typescript
|
|
181
|
+
const checkout = PaypercutCheckout({
|
|
182
|
+
id: 'CHK_12345',
|
|
183
|
+
containerId: '#checkout-container',
|
|
184
|
+
form_only: true // No Pay Now button inside checkout
|
|
185
|
+
});
|
|
186
|
+
|
|
187
|
+
// Use your own button to trigger payment
|
|
188
|
+
document.getElementById('my-pay-button').addEventListener('click', () => {
|
|
189
|
+
checkout.submit();
|
|
190
|
+
});
|
|
191
|
+
```
|
|
192
|
+
|
|
135
193
|
### Instance Methods
|
|
136
194
|
|
|
137
195
|
#### `render()`
|
|
@@ -197,39 +255,125 @@ if (checkout.isMounted()) {
|
|
|
197
255
|
|
|
198
256
|
## Events
|
|
199
257
|
|
|
200
|
-
Subscribe to events using the `on()` method
|
|
258
|
+
Subscribe to events using the `on()` method. You can use string event names or the `SdkEvent` enum.
|
|
259
|
+
|
|
260
|
+
### Event Reference
|
|
261
|
+
|
|
262
|
+
| Event | Enum | Description | Payload |
|
|
263
|
+
|-------|------|-------------|---------|
|
|
264
|
+
| `loaded` | `SdkEvent.Loaded` | Checkout iframe has finished loading | `void` |
|
|
265
|
+
| `success` | `SdkEvent.Success` | Payment completed successfully | `PaymentSuccessPayload` |
|
|
266
|
+
| `error` | `SdkEvent.Error` | Terminal failure (tokenize, confirm, or 3DS) | `ApiErrorPayload` |
|
|
267
|
+
| `expired` | `SdkEvent.Expired` | Checkout session expired | `void` |
|
|
268
|
+
| `threeds_started` | `SdkEvent.ThreeDSStarted` | 3DS challenge flow started | `object` |
|
|
269
|
+
| `threeds_complete` | `SdkEvent.ThreeDSComplete` | 3DS challenge completed | `object` |
|
|
270
|
+
| `threeds_canceled` | `SdkEvent.ThreeDSCanceled` | 3DS challenge canceled by user | `object` |
|
|
271
|
+
| `threeds_error` | `SdkEvent.ThreeDSError` | 3DS challenge error | `ApiErrorPayload` or `object` |
|
|
272
|
+
|
|
273
|
+
### Usage Examples
|
|
274
|
+
|
|
275
|
+
**Using string event names:**
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
const checkout = PaypercutCheckout({ id: 'CHK_12345', containerId: '#checkout' });
|
|
279
|
+
|
|
280
|
+
checkout.on('loaded', () => {
|
|
281
|
+
console.log('Checkout loaded');
|
|
282
|
+
});
|
|
283
|
+
|
|
284
|
+
checkout.on('success', (payload) => {
|
|
285
|
+
// PaymentSuccessPayload
|
|
286
|
+
console.log('Payment successful');
|
|
287
|
+
console.log('Card brand:', payload.payment_method.brand);
|
|
288
|
+
console.log('Last 4:', payload.payment_method.last4);
|
|
289
|
+
console.log('Expiry:', payload.payment_method.exp_month + '/' + payload.payment_method.exp_year);
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
checkout.on('error', (err) => {
|
|
293
|
+
console.error('Payment error:', err.code, err.message);
|
|
294
|
+
});
|
|
295
|
+
|
|
296
|
+
checkout.on('expired', () => {
|
|
297
|
+
console.warn('Checkout session expired');
|
|
298
|
+
});
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
**Using SdkEvent enum (recommended for TypeScript):**
|
|
302
|
+
|
|
303
|
+
```ts
|
|
304
|
+
import { PaypercutCheckout, SdkEvent } from '@paypercut/checkout-js';
|
|
305
|
+
|
|
306
|
+
const checkout = PaypercutCheckout({ id: 'CHK_12345', containerId: '#checkout' });
|
|
307
|
+
|
|
308
|
+
checkout.on(SdkEvent.Loaded, () => {
|
|
309
|
+
console.log('Checkout loaded');
|
|
310
|
+
});
|
|
311
|
+
|
|
312
|
+
checkout.on(SdkEvent.Success, (payload) => {
|
|
313
|
+
console.log('Payment successful', payload.payment_method);
|
|
314
|
+
});
|
|
315
|
+
|
|
316
|
+
checkout.on(SdkEvent.Error, (err) => {
|
|
317
|
+
console.error('Payment error:', err.code, err.message);
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
checkout.on(SdkEvent.Expired, () => {
|
|
321
|
+
console.warn('Checkout session expired');
|
|
322
|
+
});
|
|
323
|
+
|
|
324
|
+
// 3DS events
|
|
325
|
+
checkout.on(SdkEvent.ThreeDSStarted, (ctx) => {
|
|
326
|
+
console.log('3DS challenge started');
|
|
327
|
+
});
|
|
201
328
|
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
| `success` | Payment completed successfully | `PaymentSuccessPayload` |
|
|
206
|
-
| `error` | Terminal failure (tokenize, confirm, or 3DS) | `ApiErrorPayload` (see details below) |
|
|
207
|
-
| `expired` | Checkout session expired | `void` |
|
|
208
|
-
| `threeds_started` | 3DS challenge flow started; SDK modal opened | `object` (flow context) |
|
|
209
|
-
| `threeds_complete` | 3DS challenge completed | `object` (auth result context) |
|
|
210
|
-
| `threeds_canceled` | 3DS challenge canceled by user | `object` (flow context) |
|
|
211
|
-
| `threeds_error` | 3DS challenge error | `ApiErrorPayload` (if provided) or `object` |
|
|
329
|
+
checkout.on(SdkEvent.ThreeDSComplete, (payload) => {
|
|
330
|
+
console.log('3DS completed');
|
|
331
|
+
});
|
|
212
332
|
|
|
333
|
+
checkout.on(SdkEvent.ThreeDSCanceled, (payload) => {
|
|
334
|
+
console.log('3DS canceled by user');
|
|
335
|
+
});
|
|
336
|
+
|
|
337
|
+
checkout.on(SdkEvent.ThreeDSError, (err) => {
|
|
338
|
+
console.error('3DS error:', err);
|
|
339
|
+
});
|
|
340
|
+
```
|
|
213
341
|
|
|
214
|
-
|
|
342
|
+
### Success Payload
|
|
343
|
+
|
|
344
|
+
The `success` event returns a `PaymentSuccessPayload` with the payment method details:
|
|
345
|
+
|
|
346
|
+
```ts
|
|
347
|
+
type PaymentSuccessPayload = {
|
|
348
|
+
payment_method: {
|
|
349
|
+
brand: string; // e.g., 'visa', 'mastercard', 'amex'
|
|
350
|
+
last4: string; // Last 4 digits of card number
|
|
351
|
+
exp_month: number; // Expiration month (1-12)
|
|
352
|
+
exp_year: number; // Expiration year (e.g., 2030)
|
|
353
|
+
};
|
|
354
|
+
};
|
|
355
|
+
```
|
|
356
|
+
|
|
357
|
+
**Example:**
|
|
215
358
|
|
|
216
359
|
```ts
|
|
217
360
|
checkout.on('success', (payload) => {
|
|
218
|
-
// payload:
|
|
219
|
-
// Example:
|
|
361
|
+
// payload:
|
|
220
362
|
// {
|
|
221
363
|
// payment_method: {
|
|
222
364
|
// brand: 'visa',
|
|
223
365
|
// last4: '4242',
|
|
224
366
|
// exp_month: 12,
|
|
225
|
-
// exp_year: 2030
|
|
367
|
+
// exp_year: 2030
|
|
226
368
|
// }
|
|
227
369
|
// }
|
|
228
|
-
|
|
370
|
+
|
|
371
|
+
console.log(`Paid with ${payload.payment_method.brand} ending in ${payload.payment_method.last4}`);
|
|
372
|
+
// Output: "Paid with visa ending in 4242"
|
|
229
373
|
});
|
|
230
374
|
```
|
|
231
375
|
|
|
232
|
-
|
|
376
|
+
### Error Handling
|
|
233
377
|
|
|
234
378
|
```ts
|
|
235
379
|
checkout.on('error', (err) => {
|
|
@@ -252,99 +396,185 @@ checkout.on('error', (err) => {
|
|
|
252
396
|
});
|
|
253
397
|
```
|
|
254
398
|
|
|
255
|
-
###
|
|
399
|
+
### Notes
|
|
256
400
|
|
|
257
|
-
|
|
401
|
+
- `error`: the SDK forwards a normalized `ApiErrorPayload` when provided by Hosted Checkout.
|
|
402
|
+
- `threeds_error`: forwards `payload.error` when available; otherwise the raw message data.
|
|
403
|
+
- `threeds_*` non-error events: payload is forwarded as-is from Hosted Checkout (shape may evolve).
|
|
258
404
|
|
|
259
|
-
|
|
260
|
-
import { PaypercutCheckout, SdkEvent } from '@paypercut/checkout-js';
|
|
405
|
+
---
|
|
261
406
|
|
|
262
|
-
|
|
407
|
+
## Form Validation for Wallet Payments
|
|
263
408
|
|
|
264
|
-
|
|
265
|
-
// e.g., show your own UI indicator or log ctx
|
|
266
|
-
});
|
|
409
|
+
When using Apple Pay or Google Pay, you may need to validate your own form fields (e.g., email, shipping address) before the wallet payment sheet opens. The SDK provides a `form_validation` event and methods to control this flow.
|
|
267
410
|
|
|
268
|
-
|
|
269
|
-
// 3DS completed successfully; Hosted Checkout will continue the flow
|
|
270
|
-
});
|
|
411
|
+
### How It Works
|
|
271
412
|
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
413
|
+
1. User clicks Apple Pay or Google Pay button in the checkout
|
|
414
|
+
2. SDK emits `form_validation` event to your code
|
|
415
|
+
3. You validate your form and call either:
|
|
416
|
+
- `completeFormValidation(wallet)` - allows wallet to proceed
|
|
417
|
+
- `failFormValidation(wallet, errors)` - blocks wallet, you show your own errors
|
|
418
|
+
4. If validation passes, the wallet payment sheet opens
|
|
275
419
|
|
|
276
|
-
|
|
277
|
-
// Normalized ApiErrorPayload when available; fallback may be a raw object
|
|
278
|
-
console.error('3DS error:', err);
|
|
279
|
-
});
|
|
280
|
-
```
|
|
420
|
+
### Event: `form_validation`
|
|
281
421
|
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
422
|
+
| Property | Type | Description |
|
|
423
|
+
|----------|------|-------------|
|
|
424
|
+
| `checkoutId` | `string` | The checkout session ID |
|
|
425
|
+
| `wallet` | `'apple_pay' \| 'google_pay'` | Which wallet button was clicked |
|
|
286
426
|
|
|
427
|
+
### Methods
|
|
287
428
|
|
|
288
|
-
|
|
429
|
+
#### `completeFormValidation(wallet)`
|
|
289
430
|
|
|
290
|
-
|
|
431
|
+
Call this when your form is valid. The wallet payment sheet will open.
|
|
291
432
|
|
|
292
|
-
```
|
|
293
|
-
|
|
433
|
+
```typescript
|
|
434
|
+
checkout.completeFormValidation('google_pay');
|
|
435
|
+
```
|
|
294
436
|
|
|
295
|
-
|
|
437
|
+
#### `failFormValidation(wallet, errors?)`
|
|
296
438
|
|
|
297
|
-
|
|
298
|
-
console.log('Checkout loaded');
|
|
299
|
-
});
|
|
439
|
+
Call this when your form has errors. The wallet will not open, and you should display your own error messages.
|
|
300
440
|
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
}
|
|
441
|
+
```typescript
|
|
442
|
+
checkout.failFormValidation('apple_pay', [
|
|
443
|
+
{ code: 'invalid_email', message: 'Please enter a valid email address' },
|
|
444
|
+
{ code: 'missing_address', message: 'Shipping address is required' }
|
|
445
|
+
]);
|
|
446
|
+
```
|
|
304
447
|
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
448
|
+
### Basic Example
|
|
449
|
+
|
|
450
|
+
```typescript
|
|
451
|
+
import { PaypercutCheckout, SdkEvent } from '@paypercut/checkout-js';
|
|
452
|
+
|
|
453
|
+
const checkout = PaypercutCheckout({
|
|
454
|
+
id: 'CHK_12345',
|
|
455
|
+
containerId: '#checkout',
|
|
456
|
+
wallet_options: ['apple_pay', 'google_pay']
|
|
308
457
|
});
|
|
309
458
|
|
|
310
|
-
|
|
311
|
-
|
|
459
|
+
// Handle form validation for wallet payments
|
|
460
|
+
checkout.on(SdkEvent.FormValidation, ({ wallet, checkoutId }) => {
|
|
461
|
+
// Validate your own form fields
|
|
462
|
+
const email = document.getElementById('email').value;
|
|
463
|
+
const isEmailValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
464
|
+
|
|
465
|
+
if (isEmailValid) {
|
|
466
|
+
// Form is valid - allow wallet to proceed
|
|
467
|
+
checkout.completeFormValidation(wallet);
|
|
468
|
+
} else {
|
|
469
|
+
// Form has errors - block wallet and show your errors
|
|
470
|
+
document.getElementById('email-error').textContent = 'Please enter a valid email';
|
|
471
|
+
checkout.failFormValidation(wallet, [
|
|
472
|
+
{ code: 'invalid_email', message: 'Please enter a valid email' }
|
|
473
|
+
]);
|
|
474
|
+
}
|
|
312
475
|
});
|
|
476
|
+
|
|
477
|
+
checkout.render();
|
|
313
478
|
```
|
|
314
479
|
|
|
315
|
-
|
|
480
|
+
### React Example
|
|
316
481
|
|
|
317
|
-
```
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
})
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
482
|
+
```tsx
|
|
483
|
+
import { useEffect, useRef, useState } from 'react';
|
|
484
|
+
import { PaypercutCheckout, CheckoutInstance, SdkEvent } from '@paypercut/checkout-js';
|
|
485
|
+
|
|
486
|
+
export function CheckoutWithForm({ checkoutId }: { checkoutId: string }) {
|
|
487
|
+
const containerRef = useRef<HTMLDivElement>(null);
|
|
488
|
+
const checkoutRef = useRef<CheckoutInstance | null>(null);
|
|
489
|
+
const [email, setEmail] = useState('');
|
|
490
|
+
const [emailError, setEmailError] = useState('');
|
|
491
|
+
|
|
492
|
+
useEffect(() => {
|
|
493
|
+
if (!containerRef.current) return;
|
|
494
|
+
|
|
495
|
+
const checkout = PaypercutCheckout({
|
|
496
|
+
id: checkoutId,
|
|
497
|
+
containerId: containerRef.current,
|
|
498
|
+
wallet_options: ['apple_pay', 'google_pay']
|
|
499
|
+
});
|
|
500
|
+
|
|
501
|
+
// Handle wallet form validation
|
|
502
|
+
checkout.on(SdkEvent.FormValidation, ({ wallet }) => {
|
|
503
|
+
const isValid = /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(email);
|
|
504
|
+
|
|
505
|
+
if (isValid) {
|
|
506
|
+
setEmailError('');
|
|
507
|
+
checkout.completeFormValidation(wallet);
|
|
508
|
+
} else {
|
|
509
|
+
setEmailError('Please enter a valid email address');
|
|
510
|
+
checkout.failFormValidation(wallet, [
|
|
511
|
+
{ code: 'invalid_email', message: 'Invalid email' }
|
|
512
|
+
]);
|
|
513
|
+
}
|
|
514
|
+
});
|
|
515
|
+
|
|
516
|
+
checkout.on('success', (payload) => {
|
|
517
|
+
console.log('Payment successful:', payload.payment_method);
|
|
518
|
+
});
|
|
519
|
+
|
|
520
|
+
checkout.render();
|
|
521
|
+
checkoutRef.current = checkout;
|
|
522
|
+
|
|
523
|
+
return () => checkout.destroy();
|
|
524
|
+
}, [checkoutId, email]);
|
|
525
|
+
|
|
526
|
+
return (
|
|
527
|
+
<div>
|
|
528
|
+
{/* Your custom form fields */}
|
|
529
|
+
<div>
|
|
530
|
+
<label htmlFor="email">Email</label>
|
|
531
|
+
<input
|
|
532
|
+
id="email"
|
|
533
|
+
type="email"
|
|
534
|
+
value={email}
|
|
535
|
+
onChange={(e) => setEmail(e.target.value)}
|
|
536
|
+
placeholder="your@email.com"
|
|
537
|
+
/>
|
|
538
|
+
{emailError && <span style={{ color: 'red' }}>{emailError}</span>}
|
|
539
|
+
</div>
|
|
540
|
+
|
|
541
|
+
{/* Checkout iframe */}
|
|
542
|
+
<div ref={containerRef} />
|
|
543
|
+
</div>
|
|
544
|
+
);
|
|
545
|
+
}
|
|
326
546
|
```
|
|
327
547
|
|
|
548
|
+
### Timeout Behavior
|
|
328
549
|
|
|
329
|
-
|
|
550
|
+
If you don't respond to the `form_validation` event within 10 seconds, the SDK will:
|
|
551
|
+
1. Emit an `error` event with code `form_validation_timeout`
|
|
552
|
+
2. Block the wallet payment from starting
|
|
330
553
|
|
|
331
|
-
|
|
554
|
+
This ensures the checkout doesn't hang indefinitely if the handler is not implemented.
|
|
332
555
|
|
|
333
|
-
|
|
556
|
+
### When to Use
|
|
334
557
|
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
}
|
|
558
|
+
Use form validation when you have:
|
|
559
|
+
- Custom email/phone fields outside the checkout iframe
|
|
560
|
+
- Shipping address forms that must be filled before payment
|
|
561
|
+
- Terms & conditions checkboxes that must be accepted
|
|
562
|
+
- Any other merchant-side validation requirements
|
|
563
|
+
|
|
564
|
+
If you don't need to validate anything, you can simply auto-approve:
|
|
565
|
+
|
|
566
|
+
```typescript
|
|
567
|
+
checkout.on('form_validation', ({ wallet }) => {
|
|
568
|
+
// No validation needed - always allow wallet to proceed
|
|
569
|
+
checkout.completeFormValidation(wallet);
|
|
570
|
+
});
|
|
345
571
|
```
|
|
346
572
|
|
|
347
|
-
|
|
573
|
+
---
|
|
574
|
+
|
|
575
|
+
## Types
|
|
576
|
+
|
|
577
|
+
### ApiErrorPayload
|
|
348
578
|
|
|
349
579
|
The SDK forwards the error payload provided by Hosted Checkout. Common shapes include:
|
|
350
580
|
|
|
@@ -505,15 +735,19 @@ Tip: Prefer subscribing with the SdkEvent enum for stronger typing.
|
|
|
505
735
|
<body>
|
|
506
736
|
<div id="checkout"></div>
|
|
507
737
|
|
|
508
|
-
<script src="https://cdn.jsdelivr.net/npm/@paypercut/checkout-js@1.0.
|
|
738
|
+
<script src="https://cdn.jsdelivr.net/npm/@paypercut/checkout-js@1.0.13/dist/paypercut-checkout.iife.min.js"></script>
|
|
509
739
|
<script>
|
|
510
740
|
const checkout = PaypercutCheckout({
|
|
511
741
|
id: 'CHK_12345',
|
|
512
|
-
containerId: '#checkout'
|
|
742
|
+
containerId: '#checkout',
|
|
743
|
+
locale: 'en',
|
|
744
|
+
ui_mode: 'embedded',
|
|
745
|
+
wallet_options: ['apple_pay', 'google_pay']
|
|
513
746
|
});
|
|
514
747
|
|
|
515
|
-
checkout.on('success', function() {
|
|
516
|
-
|
|
748
|
+
checkout.on('success', function(payload) {
|
|
749
|
+
// payload.payment_method: { brand, last4, exp_month, exp_year }
|
|
750
|
+
alert('Payment successful with ' + payload.payment_method.brand + ' ending in ' + payload.payment_method.last4);
|
|
517
751
|
});
|
|
518
752
|
|
|
519
753
|
checkout.on('error', function(error) {
|
|
@@ -533,11 +767,17 @@ import { PaypercutCheckout } from '@paypercut/checkout-js';
|
|
|
533
767
|
|
|
534
768
|
const checkout = PaypercutCheckout({
|
|
535
769
|
id: 'CHK_12345',
|
|
536
|
-
containerId: '#checkout'
|
|
770
|
+
containerId: '#checkout',
|
|
771
|
+
locale: 'auto',
|
|
772
|
+
ui_mode: 'embedded',
|
|
773
|
+
wallet_options: ['apple_pay', 'google_pay'],
|
|
774
|
+
form_only: false
|
|
537
775
|
});
|
|
538
776
|
|
|
539
|
-
checkout.on('success', () => {
|
|
777
|
+
checkout.on('success', (payload) => {
|
|
778
|
+
// payload.payment_method: { brand, last4, exp_month, exp_year }
|
|
540
779
|
console.log('Payment successful');
|
|
780
|
+
console.log(`Paid with ${payload.payment_method.brand} **** ${payload.payment_method.last4}`);
|
|
541
781
|
// Redirect to success page
|
|
542
782
|
window.location.href = '/success';
|
|
543
783
|
});
|
|
@@ -557,17 +797,29 @@ checkout.render();
|
|
|
557
797
|
import { useEffect, useRef, useState } from 'react';
|
|
558
798
|
import { PaypercutCheckout, CheckoutInstance } from '@paypercut/checkout-js';
|
|
559
799
|
|
|
800
|
+
interface PaymentMethod {
|
|
801
|
+
brand: string;
|
|
802
|
+
last4: string;
|
|
803
|
+
exp_month: number;
|
|
804
|
+
exp_year: number;
|
|
805
|
+
}
|
|
806
|
+
|
|
560
807
|
export function CheckoutComponent({ checkoutId }: { checkoutId: string }) {
|
|
561
808
|
const containerRef = useRef<HTMLDivElement>(null);
|
|
562
809
|
const checkoutRef = useRef<CheckoutInstance | null>(null);
|
|
563
810
|
const [status, setStatus] = useState<'idle' | 'loading' | 'success' | 'error'>('idle');
|
|
811
|
+
const [paymentMethod, setPaymentMethod] = useState<PaymentMethod | null>(null);
|
|
564
812
|
|
|
565
813
|
useEffect(() => {
|
|
566
814
|
if (!containerRef.current) return;
|
|
567
815
|
|
|
568
816
|
const checkout = PaypercutCheckout({
|
|
569
817
|
id: checkoutId,
|
|
570
|
-
containerId: containerRef.current
|
|
818
|
+
containerId: containerRef.current,
|
|
819
|
+
locale: 'auto',
|
|
820
|
+
ui_mode: 'embedded',
|
|
821
|
+
wallet_options: ['apple_pay', 'google_pay'],
|
|
822
|
+
form_only: false
|
|
571
823
|
});
|
|
572
824
|
|
|
573
825
|
checkout.on('loaded', () => {
|
|
@@ -575,9 +827,10 @@ export function CheckoutComponent({ checkoutId }: { checkoutId: string }) {
|
|
|
575
827
|
console.log('Checkout loaded');
|
|
576
828
|
});
|
|
577
829
|
|
|
578
|
-
checkout.on('success', () => {
|
|
830
|
+
checkout.on('success', (payload) => {
|
|
579
831
|
setStatus('success');
|
|
580
|
-
|
|
832
|
+
setPaymentMethod(payload.payment_method);
|
|
833
|
+
console.log('Payment successful:', payload.payment_method);
|
|
581
834
|
});
|
|
582
835
|
|
|
583
836
|
checkout.on('error', (error) => {
|
|
@@ -597,7 +850,9 @@ export function CheckoutComponent({ checkoutId }: { checkoutId: string }) {
|
|
|
597
850
|
<div>
|
|
598
851
|
<div ref={containerRef} style={{ width: '100%', height: '600px' }} />
|
|
599
852
|
{status === 'loading' && <p>Processing payment...</p>}
|
|
600
|
-
{status === 'success' &&
|
|
853
|
+
{status === 'success' && paymentMethod && (
|
|
854
|
+
<p>✅ Payment successful with {paymentMethod.brand} ending in {paymentMethod.last4}!</p>
|
|
855
|
+
)}
|
|
601
856
|
{status === 'error' && <p>❌ Payment failed. Please try again.</p>}
|
|
602
857
|
</div>
|
|
603
858
|
);
|