@primer-io/checkout-web 2.0.0-alpha.3 → 2.0.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.
package/README.md CHANGED
@@ -1,1071 +1,668 @@
1
- # `@primer-io/checkout-web`
1
+ <br/>
2
2
 
3
- Using the [Primer](https://primer.io) SDK for the web, you can quickly and easily create a checkout page for your site to securely collect card information and offer a multitude of alternative payment methods to your customers through one simple integration.
3
+ <h1 align="center"><img src="https://github.com/primer-io/example-web-checkout/blob/master/images/primer-logo.png?raw=true" height="24px"> Primer Web SDK</h1>
4
4
 
5
- # Get Started!
5
+ <div align="center">
6
+ <h3 align="center">
6
7
 
7
- Check out our guides on how to get started [here](https://primer.io/docs/guides/quick-start-guide).
8
+ [Primer's](https://primer.io) Official Universal Checkout Web SDK
8
9
 
9
- Since the SDK must be loaded through our CDN. This npm package exposes a function `loadPrimer` that loads the Primer SDK from our CDN.
10
- This function returns a promise that resolves to a `class Primer`.
10
+ </h3>
11
+ </div>
12
+
13
+ <p align="center">
14
+
15
+ <img src="https://img.shields.io/npm/v/@primer-io/checkout-web" />
16
+ <!-- Potentially add test coverage in the future -->
17
+ </p>
18
+
19
+ <br/>
20
+
21
+ <div align="center"><img src="https://github.com/primer-io/example-web-checkout/blob/master/images/checkout-banner.gif?raw=true" width="50%"/></div>
22
+
23
+ <br/>
24
+ <br/>
25
+
26
+ # 💪 Features of the Web SDK
27
+
28
+ <p>💳 &nbsp; Create great payment experiences with our highly customizable Universal Checkout</p>
29
+ <p>🧩 &nbsp; Connect and configure any new payment method without a single line of code</p>
30
+ <p>✅ &nbsp; Dynamically handle 3DS 2.0 across processors and be SCA ready</p>
31
+ <p>♻️ &nbsp; Store payment methods for one-click checkout, recurring and repeat payments</p>
32
+ <p>📱 &nbsp; Proprietary Apple & Google Pay integrations that work with any PSP</p>
33
+ <p>🔒 &nbsp; Always PCI compliant without redirecting customers</p>
34
+
35
+ <br/>
36
+
37
+ # 📚 Documentation
38
+
39
+ Consider looking at the following resources:
40
+
41
+ - [Documentation](https://primer.io/docs)
42
+ - [Client session creation](https://primer.io/docs/accept-payments/manage-client-sessions/#create-a-client-session)
43
+ - [API reference](https://apiref.primer.io/docs)
44
+ - [Changelogs](https://primer.io/docs/changelog/sdk-changelog/web)
45
+
46
+ <br/>
47
+
48
+ # 💡 Support
49
+
50
+ For any support or integration related queries, feel free to [Contact Us](mailto:https://support@primer.io).
51
+
52
+ <br/>
53
+
54
+ ## 🚀 Quick start
55
+
56
+ Take a look at our [Quick Start Guide](https://primer.io/docs/integration-builder/) for accepting your first payment with Universal Checkout.
57
+
58
+ <br/>
59
+
60
+ # 📋 Prerequisites
61
+
62
+ - 🔑 Generate a client token by [creating a client session](https://primer.io/docs/api/#operation/create_client_side_token_client_session_post) in your backend
63
+ - 🧱 Prepare a container in which to render Universal Checkout
64
+ - 🎉 _That's it!_
65
+
66
+ <br/>
67
+
68
+ # 🧱 Installation
69
+
70
+ ## With npm (recommended)
71
+
72
+ Our Web SDK is available on npm under the name [`@primer-io/checkout-web`](https://www.npmjs.com/package/@primer-io/checkout-web).
73
+
74
+ This package includes TypeScript definitions.
75
+
76
+ ```bash
77
+
78
+ # With yarn
79
+ yarn add @primer-io/checkout-web
80
+
81
+ # With npm
82
+ npm install --save @primer-io/checkout-web
11
83
 
12
84
  ```
13
- import {loadPrimer} from '@primer-io/checkout-web'
14
85
 
15
- const Primer = await loadPrimer();
16
- const client = new Primer({
17
- credentials: { clientToken: "...", },
86
+ ```typescript
87
+ import { Primer } from '@primer-io/checkout-web';
88
+
89
+ Primer.showUniversalCheckout(clientToken, {
90
+ /* Options */
18
91
  });
19
92
  ```
20
93
 
21
- # Reference
94
+ ## With our CDN
22
95
 
23
- ## Global
96
+ Include the `Primer.min.js` script on the page where you want the checkout to be rendered.
24
97
 
25
- ### `class Primer(options: PrimerClientOptions)`
98
+ Ensure that you're providing the desired version in the script tag. In the case below, it's `v2.0.0`:
26
99
 
27
- Creates a primer client
100
+ ```html
101
+ <link rel="stylesheet" href="https://sdk.primer.io/web/v2.0.0/Checkout.css" />
28
102
 
29
- ### `type PrimerClientOptions`
103
+ <script
104
+ src="https://sdk.primer.io/web/v2.0.0/Primer.min.js"
105
+ crossorigin="anonymous"
106
+ ></script>
107
+ ```
30
108
 
31
- Options to configure the primer client
109
+ `Primer.min.js` will add the Primer object to the global scope:
32
110
 
33
111
  ```typescript
34
- type PrimerClientOptions {
35
- credentials: {
36
- // Your server-generated client token
37
- clientToken: string;
38
- };
39
-
40
- // maximum time in milliseconds to wait for third party scripts to load [default=10000]
41
- thirdPartyScriptTimeout?: number;
42
- }
112
+ const { Primer } = window;
113
+
114
+ Primer.showUniversalCheckout(clientToken, {
115
+ /* Options */
116
+ });
43
117
  ```
44
118
 
45
- ---
119
+ <br/>
46
120
 
47
- ## Primer (checkout)
121
+ ## 👩‍💻 Usage
48
122
 
49
- ### `Primer#checkout(options: Options): Promise<PrimerCheckout>`
123
+ ### 🔍 &nbsp;Rendering the checkout
50
124
 
51
- Create a Primer checkout component. The structure of `options` depends on `options.uxFlow`, which can have three values:
125
+ Availing Universal Checkout is as easy as implementing one line of code:
52
126
 
53
- - `CHECKOUT`: to render a checkout that displays multiple payment methods and the vaulted payment methods
54
- - `SINGLE_PAYMENT_METHOD_CHECKOUT`: to render a checkout that displays a single payment method
55
- - `MANAGE_PAYMENT_METHODS`: to render a UI for managing saved payment methods
127
+ ```javascript
128
+ import { Primer } from '@primer-io/checkout-web';
56
129
 
57
- By default, `uxFlow` is `CHECKOUT`.
130
+ const universalCheckout = await Primer.showUniversalCheckout(
131
+ clientToken,
132
+ options,
133
+ );
134
+ ```
58
135
 
59
- ### Common options
136
+ Below is an example of a basic implementation of Universal Checkout:
60
137
 
61
- Some options are common to all `uxFlow`.
138
+ ```javascript
139
+ const clientToken = '...'; // client token retrieved from your backend
62
140
 
63
- ```typescript
64
- type Options = {
65
- // Optimise the UX for managing saved payment methods by specifying 'MANAGE_PAYMENT_METHODS' for uxFlow
66
- uxFlow: 'CHECKOUT' | 'MANAGE_PAYMENT_METHODS' | 'SINGLE_PAYMENT_METhOD_CHECKOUT,
141
+ const options = {
142
+ // Container element which will contain the checkout
143
+ container: '#container',
67
144
 
68
- // An HTML element (or a selector to the HTML element) in which to place the checkout component
69
- container: string | Element;
145
+ onCheckoutComplete({ payment }) {
146
+ // Notifies you that a payment was created
147
+ // Move on to next step in your checkout flow:
148
+ // e.g. Show a success message, giving access to the service, fulfilling the order
149
+ },
150
+ };
70
151
 
71
- // Override the locale
72
- // By default translations will be provided for the browser's locale
73
- locale?: string;
152
+ const universalCheckout = await Primer.showUniversalCheckout(
153
+ clientToken,
154
+ options,
155
+ );
156
+ ```
74
157
 
75
- // 3DS options. These must be provided if you want to perform SCA
76
- // See the section on 3DS below for more info.
77
- threeDSecure?: ThreeDSecureVerifyOptions;
158
+ Note that there are more options which can be passed to Universal Checkout. Please refer to the section below for more information.
78
159
 
79
- // A callback for when tokenization begins
80
- onTokenizeStart?: () => void;
160
+ <br/>
81
161
 
82
- // A callback for tokenization success. This will receive the payment method token.
83
- onTokenizeSuccess: (data: PaymentMethodToken) => Promise<SuccessCallbackReturnType>;
162
+ ## 🧰 &nbsp;Checkout Options
84
163
 
85
- // A callback for when tokenization fails. See the error message here for more information
86
- onTokenizeError: (message: string) => void;
164
+ When calling `showUniversalCheckout` you can provide Universal Checkout with some configuration options.
87
165
 
88
- // A callback for when changes have been made to the totalAmount provided to the checkout
89
- onAmountChange?: (data: AmountChange) => void;
166
+ These options range from callbacks notifying you of the current payment's status, to styling options for certain UI elements.
90
167
 
91
- // A callback for when changes totalAmount is being updated
92
- onAmountChanging?: (isChanging: boolean) => void;
168
+ Below are some options to consider when integrating Universal Checkout:
93
169
 
94
- // A callback for when an error occured while updating the totalAmount
95
- onAmountChangeError?: (message: PrimerError) => void;
170
+ ### 🚀 **General Options**
96
171
 
97
- // A callback for receiving actions which can be used to update the client session
98
- onClientSessionActions?: (data: onClientSessionActionData) => Promise<{ clientToken: string } | false>;
172
+ #### ⚙️ _Container and locale_
99
173
 
100
- // Options and callbacks relating to scenes
101
- scene?: SceneOptions;
174
+ | option | Type | Description | |
175
+ | ----------- | --------------------- | ----------------------------------------------------------------------------------------- | -------- |
176
+ | `container` | `string` or `Element` | The container element in which the checkout should be rendered | required |
177
+ | `locale` | `string` | This option forces the locale. By default, the locale will be set to the browser's locale | optional |
102
178
 
103
- // Style of the Checkout
104
- style?: CheckoutStyle;
179
+ <br/>
105
180
 
106
- // Set options relating to the card form
107
- form?: FormOptions;
181
+ #### ⚙️ _Payment Lifecycle Callbacks_
108
182
 
109
- submitButton?: {
110
- // Deprecated in favor of using `useBuiltInButton`
111
- visible?: boolean;
183
+ Callbacks can be provided to Universal Checkout which will notify you on certain checkout events such as payment creation.
112
184
 
113
- // Set whether to use built-in submit button
114
- // Or use your own submit button
115
- // Defaults to true
116
- useBuiltInButton?: boolean;
185
+ These callbacks can be used to inform you on the current state of the checkout.
117
186
 
118
- // The following callbacks can be used to update your custom submit button
119
- // Ensuring that your button has the correct state and content for a specific scene
187
+ We strongly recommend you to implement `onCheckoutComplete` to redirect the user to an order confirmation page when the payment is successful:
120
188
 
121
- // Callback for receiving the submit button's visible state in the current scene
122
- onVisible: (isVisible: boolean, context: { currentSceneId: string; } ) => void;
189
+ ```javascript
190
+ const options = {
191
+ /* Other checkout options ... */
123
192
 
124
- // Callback for receiving the submit button's disabled state in the current scene
125
- onDisable: (isDisabled: boolean, context: { currentSceneId: string }) => void;
193
+ onBeforePaymentCreate(data, handler) {
194
+ // Notifies you that a payment will be created
195
+ // Update your UI accordingly
196
+ // e.g. Show custom loading UI, etc.
197
+ // Abort or continue with payment creation
198
+ // Primer will continue with payment creation if onBeforePaymentCreate is not implemented
126
199
 
127
- // Callback for receiving the submit button's loading state in the current scene
128
- onLoading: (isLoading: boolean, context: { currentSceneId: string }) => void;
200
+ // ⚠️ You MUST call one of the functions of the `handler` if `onBeforePaymentCreate` is implemented
129
201
 
130
- // Callback for receiving the submit button's content in the current scene
131
- onContentChange: (content: string, context: { currentSceneId: string }) => void;
132
- };
133
-
134
- processingIndicator?: {
135
- // Show a processing indicator overlay on top of the checkout when submitting a form
136
- // Default to false if the submit button is visible
137
- // Default to true if the submit button is hidden
138
- visible?: boolean;
139
- };
140
-
141
- // Handles the error message displayed below the submit button when an error occurs
142
- errorMessage?: {
143
- // Disable the appearance of the default error message
144
- // Default to false
145
- disabled?: boolean;
146
-
147
- // A callback for when the error message is displayed
148
- onErrorMessageShow?: (message: string) => void;
149
-
150
- // A callback for when the error message is hidden
151
- onErrorMessageHide?: () => void;
152
- }
153
-
154
- /* PAYMENT METHOD SPECIFIC */
155
-
156
- // Card networks allowed for checkout
157
- // An error will be showed to the customer if they attempt to pay with a card network that is not allowed, whether it is using a card form, or via Google Pay/Apple Pay/...
158
- // By default, all card networks are allowed
159
- allowedCardNetworks: CardNetwork[];
160
-
161
- card?: CheckoutCardOptions;
162
- paypal?: PayPalOptions;
163
- googlePay?: GooglePayOptions;
164
- applePay?: ApplePayOptions;
165
- directDebit?: DirectDebitOptions;
166
-
167
- redirect?: {
168
- // URL to return to in case of a redirect
169
- returnUrl?: string;
170
-
171
- // Default to false. Set to true to force a redirect for testing purposes.
172
- forceRedirect?: boolean;
173
- }
174
- }
175
- ```
202
+ // Choose to abort a payment
203
+ return handler.abortPaymentCreation();
176
204
 
177
- ```typescript
178
- type CardNetwork =
179
- | 'american-express'
180
- | 'diners-club'
181
- | 'discover'
182
- | 'elo'
183
- | 'hiper'
184
- | 'hipercard'
185
- | 'interac'
186
- | 'jcb'
187
- | 'maestro'
188
- | 'mastercard'
189
- | 'mir'
190
- | 'unionpay'
191
- | 'visa';
192
- ```
205
+ // Choose to continue with payment creation
206
+ return handler.continuePaymentCreation();
207
+ },
193
208
 
194
- ```typescript
195
- type SuccessCallbackReturnType =
196
- | /* Show success screen (for backward compability) */ undefined
197
- | /* Show success screen */ true
198
- | /* Refresh client token and perform new step */ { clientToken: string };
199
- ```
209
+ onCheckoutComplete({ payment }) {
210
+ // Notifies you that a payment was created
211
+ // Move on to next step in your checkout flow:
212
+ // e.g. Show a success message, giving access to the service, fulfilling the order, ...
213
+ },
200
214
 
201
- ### Client session actions
215
+ onCheckoutFail(error, { payment }, handler) {
216
+ // Notifies you that the checkout flow has failed and a payment could not be created
217
+ // This callback can also be used to display an error state within your own UI.
202
218
 
203
- The checkout has the ability to return actions in the `onClientSessionActions` callback. These actions should be sent to your backend and forwarded to Primer's `/client-session/actions` endpoint. Actions have the ability to mutate the client session when certain events occur, based on pre-defined conditions. The following types describe what could be returned in `onClientSessionActions`:
219
+ // ⚠️ `handler` is undefined if the SDK does not expect anything from you
220
+ if (!handler) {
221
+ return;
222
+ }
204
223
 
205
- ```typescript
206
- // The data returned in onClientSessionActions
207
- type ClientSessionActionData = {
208
- actions: ClientSessionAction[];
209
- clientToken: string;
210
- };
211
- ```
224
+ // ⚠️ If `handler` exists, you MUST call one of the functions of the handler
212
225
 
213
- ```typescript
214
- type ClientSessionAction = {
215
- type: ActionType;
216
- params: ActionsParameters;
226
+ // Show a default error message
227
+ return handler.showErrorMessage();
228
+
229
+ // Show a custom error message
230
+ return handler.showErrorMessage('This is my custom error message');
231
+ },
217
232
  };
218
233
  ```
219
234
 
220
- ```typescript
221
- // The currently supported action types forwarded to onClientSessionActions
222
- type ActionType = 'SELECT_PAYMENT_METHOD' | 'UNSELECT_PAYMENT_METHOD';
223
- ```
235
+ <br/>
224
236
 
225
- ```typescript
226
- type ActionParameters = SelectPaymentMethodParamters | DefaulActionParameters;
227
- ```
237
+ #### ⚙️ _Client Session Lifecycle Callbacks_
228
238
 
229
- ```typescript
230
- type SelectPaymentMethodParamters = {
231
- paymentMethodType: string;
232
- binData?: BinData;
233
- };
234
- ```
239
+ Callbacks can be provided to Universal Checkout which will notify you on client session update events.
235
240
 
236
- ```typescript
237
- type DefaulActionParameters = {
238
- type: string;
239
- };
240
- ```
241
+ ```javascript
242
+ const options = {
243
+ /* Other checkout options ... */
241
244
 
242
- ### Specific options to `CHECKOUT`
245
+ onBeforeClientSessionUpdate() {
246
+ // Notifies you that the client session is in the process of being updated
247
+ // Use it to show a loading indicator on your UI
248
+ },
243
249
 
244
- ```typescript
245
- type CheckoutOptions = {
246
- // By default, all payment methods configured in the dashboard are proposed in the Checkout
247
- // This filters the payment methods available
248
- allowedPaymentMethods?: PaymentMethodType[];
249
-
250
- // Additional information relating to merchant operating address. Used for tax calculation
251
- businessDetails?: {
252
- address: {
253
- countryCode: string;
254
- state: string;
255
- postalCode: string;
256
- city: string;
257
- addressLine1: string;
258
- };
259
- nexusAddresses: [
260
- {
261
- countryCode: string;
262
- state: string;
263
- postalCode: string;
264
- city: string;
265
- addressLine1: string;
266
- },
267
- ];
268
- };
269
-
270
- // Additional information relating to customer. Details can be used for tax calculation
271
- customerDetails?: {
272
- customerTaxId: string;
273
- shippingAddress: {
274
- countryCode: string;
275
- state: string;
276
- postalCode: string;
277
- city: string;
278
- addressLine1: string;
279
- };
280
- };
281
-
282
- // Options regarding the vault and one-click checkout feature
283
- vault?: {
284
- // Fetch the vaulted payment methods of the customerId of the current session and display them
285
- // Default to true
286
- visible?: boolean;
287
-
288
- // Disable the option to delete a saved payment method.
289
- // Default to false
290
- deletionDisabled?: boolean;
291
- };
292
-
293
- // A callback for when a resume action succeeds. This will receive the resume token used to resume a payment
294
- onResumeSuccess: (data: ResumeToken) => Promise<SuccessCallbackReturnType>;
295
-
296
- // A callback for when an error happened when resuming
297
- onResumeError: (error: PrimerClientError) => void;
250
+ onClientSessionUpdate(clientSession) {
251
+ // Notifies you when the client session has been updated by the checkout
252
+ // Returns updated client session
253
+ // Updated client session can be used to inform your UI
254
+ // e.g. update tax, shipping or discount amounts displayed to your customers
255
+ },
298
256
  };
299
257
  ```
300
258
 
301
- ```typescript
302
- enum PaymentMethodType {
303
- PAYMENT_CARD = 'PAYMENT_CARD',
304
- APPLE_PAY = 'APPLE_PAY',
305
- GOOGLE_PAY = 'GOOGLE_PAY',
306
- PAYPAL = 'PAYPAL',
307
- GO_CARDLESS = 'GOCARDLESS',
308
- }
309
- ```
259
+ ---
310
260
 
311
- ```typescript
312
- interface FormOptions {
313
- inputLabelsVisible?: boolean; // Show or hide form input labels
314
- }
315
- ```
261
+ ### 💳 **Payment Methods Options**
316
262
 
317
- ```typescript
318
- type SceneOptions = {
319
- // A callback for receiving the current scene that is entering
320
- onEntering?: (sceneId: string) => void;
321
-
322
- // Specify options relating to scene transitions
323
- // Setting to false disables all scene transitions
324
- // Defaults to a 'SLIDE_UP' type transition with a duration of 700ms
325
- transition?: SceneTransitionOptions | false
326
- }
327
-
328
- type SceneTransitionOptions = {
329
- // The type of transition animation which will be used
330
- type: TransitionType;
331
- // The duration of the transition animation
332
- duration: number;
333
- };
263
+ Learn more about the [payment method specific options](https://www.notion.so/primerio/Checkout-Documentation-589aeae3387a4025917db6e29810ebaf).
334
264
 
335
- type TransitionType =
336
- | 'SLIDE_UP'
337
- | 'SLIDE_DOWN'
338
- | 'SLIDE_HORIZONTAL
339
- ```
265
+ <!--
266
+ #### ⚙️ _Redirect Options_
340
267
 
341
- #### Dynamic Checkout Flow: `onTokenizeSuccess` and `onResumeSuccess`
268
+ Handling redirects is required for Payment Methods like iDeal that present a webpage for the customer to enter their credentials and validate their payment.
342
269
 
343
- When a payment method is chosen and the customer clicks 'Pay', the payment method is tokenized and you'll receive a payment method token in the `onTokenizeSuccess` callback. Send it to your server to **create a payment** using Primer's Payments API.
270
+ When the user selects such a Payment Method, Universal Checkout will first attempt to show the webpage in a popup or a browser tab to maintain the context, and will then safely bring the user back to the initial page to continue the flow.
344
271
 
345
- The checkout stays in a loading state while you perform this request. The Payments API may return a new client token: pass it as a return value of `onTokenizeSuccess` to perform the action tied to the new token, such as performing 3DS.
272
+ This however does not work properly in some scenario involving third-party apps through deep linking.
346
273
 
347
- ```typescript
348
- // Called after a payment method is tokenized
349
- // The checkout stays is a loading state until this Promise is resolved or rejected
350
- async onTokenizeSuccess(paymentMethod) {
351
- // Send the payment method token to your server to then create a payment
352
- const response = await sendPaymentMethodToken(paymentMethod);
353
-
354
- // If a new client token is available, resolve the Promise with it to refresh the checkout session
355
- // The checkout will automatically perform the action required by the Workflow
356
- // e.g. Perform a 3D Secure challenge
357
- if (response.clientToken) {
358
- return { clientToken: response.clientToken };
359
- }
360
-
361
- // Display the success screen
362
- return true;
363
- }
364
- ```
274
+ | option | Type | Description | Default | |
275
+ | ------------------------ | ------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | -------- |
276
+ | `redirect.returnUrl` | String | If creating a popup or tab is not possible, Universal Checkout will automatically redirect the user back to this URL. | | optional |
277
+ | `redirect.forceRedirect` | Boolean | Forces redirect instead of using popups. <br /> _This negatively affects the User Experience. We recommend to only use this option in your testing environment._ | false | optional |
365
278
 
366
- When the new action commanded by the Payments API is completed, you'll receive a resume token via the `onResumeSuccess` callback. Send it to your server to **resume a payment** using Primer's Payments API.
279
+ #### ⚙️ _Card Options_
367
280
 
368
- The checkout stays in a loading state while you perform this request. The Payments API may return a new client token: pass it as a return value of `onResumeSuccess` to perform the action tied to the new token.
281
+ These options only apply to the native Card implementation (`PAYMENT_CARD`).
369
282
 
370
- ```typescript
371
- // Called after an extra-step - such as performing 3D Secure - is completed
372
- // The checkout stays is a loading state until this Promise is resolved or rejected
373
- async onResumeSuccess({resumeToken}) {
374
-
375
- // Send the payment method token to your server to then create a payment
376
- const response = await sendResumeToken(resumeToken);
377
-
378
- // If a new client token is available, resolve the Promise with it to refresh the checkout session
379
- // The checkout will automatically perform the action required by the Workflow
380
- if (response.clientToken) {
381
- // e.g. Trigger a 3D Secure challenge
382
- return { clientToken: response.clientToken };
383
- }
384
-
385
- // Display the success screen
386
- return true;
387
- }
388
- ```
283
+ | option | Type | Description | Default | |
284
+ | ----------------------------- | --------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- | -------- |
285
+ | `card.preferredFlow` | `DEDICATED_SCENE` or `EMBEDDED_IN_HOME` | `DEDICATED_SCENE`<br />Attempt to display a card button in the home scene. Clicking on this button will show the card form. <br /> <br /> `EMBEDDED_IN_HOME`<br /> Attempt to display the entire card form within the home scene. | `EMBEDDED_IN_HOME` | optional |
286
+ | `card.cardNumber.placeholder` | String | Placeholder for the card number field. | `1234 1234 1234 1234` | optional |
287
+ | `card.expiryDate.placeholder` | String | Placeholder for the card number field. | Localized version of `MM/YY` | optional |
288
+ | `card.expiryDate.cvv` | String | Placeholder for the card number field. | `***` or `****` depending on the card scheme | optional |
389
289
 
390
- ### Specific options to `MANAGE_PAYMENT_METHODS`
290
+ ---
391
291
 
392
- ```typescript
393
- orderDetails?: {
394
- currencyCode: string;
395
- };
292
+ #### ⚙️ _Apple Pay Options_
396
293
 
397
- // Disable the option to delete a saved payment method.
398
- // Default to false
399
- deletionDisabled?: boolean;
400
- ```
294
+ These options only apply to the native Apple Pay implementation (`APPLE_PAY`).
401
295
 
402
- ### Specific options to `SINGLE_PAYMENT_METHOD_CHECKOUT`
296
+ | option | Type | Description | Default | |
297
+ | ---------------------- | ------------------------------------------------------------------- | -------------------------------------------- | ------- | -------- |
298
+ | `applePay.buttonType` | `plain`, `buy`, `set-up`, `donate`, `check-out`, `book`, `suscribe` | Control the content of the Apple Pay button. | `plain` | optional |
299
+ | `applePay.buttonStyle` | `white`, `white-outline`, `black` | Control the style of button. | `black` | optional |
403
300
 
404
- ```typescript
405
- type SinglePaymentMethodCheckoutOptions = {
406
- // The single payment method to render
407
- // Only "GOCARDLESS" at the moment
408
- paymentMethod: PaymentMethodType;
409
- };
410
- ```
301
+ #### ⚙️ _Google Pay Options_
411
302
 
412
- ### Specific to payment methods
303
+ These options only apply to the native Google Pay implementation (`GOOGLE_PAY`).
413
304
 
414
- #### `CheckoutCardOptions`
305
+ | option | Type | Description | Default | |
306
+ | ---------------------- | --------------------------- | ------------------------------------------- | --------- | -------- |
307
+ | `googlePay.buttonType` | `long`, `short` | Control the size of the Google Pay button. | `long` | optional |
308
+ | `google.buttonColor` | `default`, `black`, `white` | Control the color of the Google Pay button. | `default` | optional |
415
309
 
416
- ```typescript
417
- type CheckoutCardOptions = {
418
- // A stylesheet to inject into each input element
419
- // For more information see the guide on styling
420
- css?: string;
421
-
422
- // deprecated after v1.2.0
423
- // Choose if the cardholder name should be required or not
424
- // default value is true
425
- cardholderNameRequired?: boolean;
426
-
427
-
428
- cardholderName?: {
429
- // Choose if the cardholder name should be visible
430
- // default value is true
431
- visible?: boolean;
432
-
433
- // Choose if the cardholder name should be required
434
- // If visible, the default value is true
435
- required?: boolean;
436
-
437
- // Placeholder text which will be displayed within input
438
- // defaults to localized placeholder if not provided
439
- placeholder?: string;
440
- };
441
-
442
- cardNumber?: {
443
- // Placeholder card number which will be displayed within input
444
- // default card number placeholder displayed if not provided
445
- placeholder?: string;
446
- };
447
-
448
- expiryDate?: {
449
- // Placeholder expiry date which will be displayed within input
450
- // default expiry date placeholder displayed if not provided
451
- placeholder?: Label;
452
- };
453
-
454
- cvv?: {
455
- // Placeholder cvv which will be displayed within input
456
- // default cvv placeholder displayed if not provided
457
- placeholder?: Label;
458
- };
459
-
460
- // Choose if the card form should be embedded in the home scene
461
- // Or have a dedicated card scene accessible by a card button
462
- // Note that the preferredFlow will not necessarily be the chosen flow
463
- preferredFlow?: CardPreferredFlow;
464
-
465
- // Checkout will ask the customer id they want to save their card.
466
- // To disable this feature provide a value for the vault option.
467
- // When true: the card will be vaulted
468
- // When false: the card will not be vaulted
469
- vault?: boolean | () => boolean;
470
- };
471
-
472
- // DEDICATED_SCENE: can be used if more than one payment method is available
473
- // EMBEDDED_IN_HOME: is provided by default. It will override the dedicated scene option
474
- // When card is the only available payment method
475
- type CardPreferredFlow = 'DEDICATED_SCENE' | 'EMBEDDED_IN_HOME';
476
- ```
310
+ #### ⚙️ _PayPal Options_
477
311
 
478
- #### `PayPalOptions`
312
+ These options only apply to the native PayPal implementation (`PAYPAL`).
479
313
 
480
- ```typescript
481
- type PayPalOptions = {
482
- buttonColor?: 'gold' | 'blue' | 'silver' | 'white' | 'black';
483
- buttonShape?: 'pill' | 'rect';
484
- buttonSize?: 'small' | 'medium' | 'large' | 'responsive';
485
- buttonHeight?: number;
486
- buttonLabel?:
487
- | 'checkout'
488
- | 'credit'
489
- | 'pay'
490
- | 'buynow'
491
- | 'paypal'
492
- | 'installment';
493
- buttonTagline?: boolean;
494
- paymentFlow?: PaymentFlow;
495
- };
496
- ```
314
+ | option | Type | Description | Default | |
315
+ | -------------------- | -------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------- | -------- |
316
+ | `paypal.buttonColor` | `gold`, `blue`, `silver`, `white`, `black` | Control the color of the PayPal button. | `gold` | optional |
317
+ | `paypal.buttonLabel` | `checkout`, `credit`, `pay`, `buynow`, `paypal`, `installment` | Control the label written in the PayPal button. | `PayPal` | optional |
318
+ | `paypal.paymentFlow` | `DEFAULT`, `PREFER_VAULT` | `DEFAULT`<br />Prepare everything to make a payment with PayPal. <br /><br />`PREFER_VAULT`<br />Vaut PayPal before making a payment. <br />Make sure the [`customerId`](https://apiref.primer.io/reference/create_client_side_token_client_session_post#request.body.customerId) is set in the client session. | `DEFAULT` | optional |
497
319
 
498
- #### `DirectDebitOptions`
320
+ #### ⚙️ _Klarna Options_
499
321
 
500
- ```typescript
501
- type DirectDebitOptions = {
502
- customerCountryCode: Alpha2CountryCode;
503
-
504
- // The following options are used in the Direct Debit mandate
505
- companyName: string;
506
- companyAddress: string;
507
-
508
- // The following options are used to prefill the Direct Debit form
509
- customerName?: string;
510
- customerEmail?: string;
511
- customerAddressLine1?: string;
512
- customerAddressLine2?: string;
513
- customerCity?: string;
514
- customerPostalCode?: string;
515
- iban?: string;
516
-
517
- // Label of the submit button
518
- submitButtonLabels?: {
519
- // Label of the submit button in the form
520
- form?: string;
521
-
522
- // Label of the submit button in the mandate
523
- mandate: string;
524
- };
525
- };
526
- ```
322
+ These options only apply to the native Klarna implementation (`KLARNA`).
527
323
 
528
- #### `ApplePayOptions`
324
+ | option | Type | Description | Default | |
325
+ | ------------------------------------ | ------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------- | -------- |
326
+ | `klarna.recurringPaymentDescription` | String |  Payment description used for recurring payments | | optional |
327
+ | `klarna.allowedPaymentCategories` | Array of categories <br /> `pay_now`, `pay_later`, `pay_over_time` | List of categories allowed to be presented to the customer | `['pay_now', 'pay_later', 'pay_over_time']` | optional |
328
+ | `klarna.paymentFlow` | `DEFAULT`, `PREFER_VAULT` | `DEFAULT`<br />Prepare everything to make a payment with Klarna. <br /><br />`PREFER_VAULT`<br />Vaut Klarna before making a payment. <br />Make sure the [`customerId`](https://apiref.primer.io/reference/create_client_side_token_client_session_post#request.body.customerId) is set in the client session. | `DEFAULT` | optional |
529
329
 
530
- ```typescript
531
- type ApplePayOptions = {
532
- buttonType?:
533
- | 'plain'
534
- | 'buy'
535
- | 'set-up'
536
- | 'donate'
537
- | 'check-out'
538
- | 'book'
539
- | 'subscribe';
540
- buttonStyle?: 'white' | 'white-outline' | 'black';
541
- };
542
- ```
330
+ -->
543
331
 
544
- #### `GooglePayOptions`
332
+ ---
545
333
 
546
- ```typescript
547
- buttonType?: "long" | "short";
548
- buttonColor?: "default" | "black" | "white";
549
- ```
334
+ ### 🎨 **Customization Options**
550
335
 
551
- ### Setters
336
+ Learn more about the [customization options](https://primer.io/docs/accept-payments/customize-universal-checkout/web).
552
337
 
553
- The checkout provides setter methods which can be called to update options after initialization.
338
+ #### ⚙️ _Styling_
554
339
 
555
- ```typescript
556
- const checkout = await primer.checkout(checkoutOptions);
340
+ | option | Type | Description | Default | |
341
+ | ------- | ------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------- | -------- |
342
+ | `style` | Object | Custom style applied to the UI. <br /> Learn more about the capabilities in our [Customization Guide](docs/accept-payments/customize-universal-checkout/web/#styling-universal-checkout) | Default style | optional |
557
343
 
558
- checkout.setClientToken(clientToken);
559
- ```
344
+ #### ⚙️ _Form Options_
560
345
 
561
- ### Manual Form Submission
346
+ | option | Type | Description | Default | |
347
+ | ------------------------- | ------- | --------------------------------------------- | ------- | -------- |
348
+ | `form.inputLabelsVisible` | Boolean | Choose whether to show the label above inputs | true | optional |
562
349
 
563
- The checkout provides a method for manually calling submit.
564
- This is useful when using your own custom submit button.
350
+ #### ⚙️ _Submit Button Options & Callbacks_
565
351
 
566
- ```typescript
567
- const checkout = await primer.checkout(checkoutOptions);
352
+ Universal Checkout allows you to use your own submit button for submitting forms. By default, the built-in submit button will be favored:
568
353
 
569
- const handleMySubmitButtonClick = () => {
570
- // Forward all submit button clicks to the SDK
571
- checkout.submit();
572
- };
573
- ```
354
+ | option | Type | Description | Default | |
355
+ | ------------------------------- | ------- | ------------------------------------------------------------------------------ | ------- | -------- |
356
+ | `submitButton.useBuiltInButton` | Boolean | Set whether to use built-in submit button or to display your own custom button | true | optional |
574
357
 
575
- ### Style
358
+ <br/>
576
359
 
577
- ```typescript
578
- interface CheckoutStyle {
579
- fontFaces?: Array<FontFace>; // Injected into hosted fields
580
- stylesheets?: Array<Stylesheet>; // Injected into hosted fields
581
-
582
- loadingScreen?: {
583
- // Color of the loading screen indicator
584
- color?: string;
585
- };
586
-
587
- // Style of the inputs
588
- input?: {
589
- // Base style
590
- base?: InputStyle & {
591
- hover?: InputStyle; // :hover
592
- focus?: InputStyle; // :focus
593
- placeholder?: InputStyle; // ::placeholder
594
- webkitAutofill?: InputStyle; // :-webkit-autofill
595
- selection?: InputStyle; // ::selection
596
- };
597
-
598
- // Error
599
- error?: InputStyle & {
600
- hover?: InputStyle;
601
- focus?: InputStyle;
602
- placeholder?: InputStyle;
603
- webkitAutofill?: InputStyle;
604
- selection?: InputStyle;
605
- };
606
- };
607
-
608
- // Style of the label displayed above the input fields
609
- inputLabel?: TextStyle;
610
-
611
- // Style of the error messages displayed below the input fields
612
- inputErrorText?: TextStyle & TextAlignmentStyle;
613
-
614
- formSpacings?: {
615
- // Vertical spacing between a label and an input field
616
- betweenLabelAndInput?: string;
617
-
618
- // Vertical spacing between inputs
619
- betweenInputs: string;
620
- };
621
-
622
- showMorePaymentMethodsButton?: {
623
- base?: TextStyle;
624
- disabled?: TextStyle;
625
- }
626
-
627
- // Style APM buttons
628
- // PayPal, Apple Pay, Google Pay and Klarna can only be styled in height and borderRadius.
629
- paymentMethodButton: {
630
- background?: string;
631
- borderRadius?: number | string;
632
- boxShadow?: string;
633
- borderColor?: string;
634
- height?: number;
635
- primaryText?: TextStyle;
636
- logoColor?: logoColor;
637
- marginTop?: string;
638
- };
639
-
640
- submitButton?: {
641
- base?: {
642
- hover?: TextStyle & BlockStyle;
643
- focus?: TextStyle & BlockStyle;
644
- };
645
-
646
- loading?: {
647
- hover?: TextStyle & BlockStyle;
648
- focus?: TextStyle & BlockStyle;
649
- };
650
- };
651
-
652
- // Small print in direct debit
653
- smallPrint?: TextStyle;
654
-
655
- directDebit?: {
656
- mandate?: {
657
- header?: TextStyle;
658
- label?: TextStyle;
659
- content?: TextStyle;
660
- creditorDetails?: TextStyle:
661
- };
662
-
663
- success?: {
664
- icon?: {
665
- color?: string;
666
- }
667
- };
668
- };
669
-
670
- backButton?: {
671
- color?: string;
672
- };
673
-
674
- // Pop-up menu to manage the vaulted payment methods
675
- vaultMenu?: {
676
- // Pencil icon
677
- editButton?: {
678
- // Backend of the pencil icon
679
- background?: string;
680
- // Color of the pencil icon
681
- color?: string;
682
- };
683
-
684
- item?: {
685
- label?: textStyle;
686
- // Delete & Cancel button
687
- actionButton?: TextStyle;
688
- confirmButton?: TextStyle & BlockStyle;
689
- };
690
- }
691
-
692
- }
693
-
694
- interface FontFace {
695
- fontFamily?: string;
696
- src?: string;
697
- unicodeRange?: string;
698
- fontVariant?: string;
699
- fontFeatureSettings?: string;
700
- fontVariationSettings?: string;
701
- fontStretch?: string;
702
- fontWeight?: string;
703
- fontStyle?: string;
704
- }
705
-
706
- interface Stylesheet {
707
- href: string;
708
- }
709
-
710
- interface TextStyle {
711
- color?: string;
712
- fontFamily?: string;
713
- fontWeight?: string;
714
- fontSize?: string;
715
- fontSmoothing?: string;
716
- lineHeight?: string;
717
- textTransform?: string;
718
- letterSpacing?: string;
719
- }
720
-
721
- interface BlockStyle {
722
- background?: string;
723
- borderRadius?: number | string;
724
- boxShadow?: string;
725
- borderStyle?: string;
726
- borderColor?: number | string;
727
- borderWidth?: number | string;
728
- }
729
-
730
- interface TextAlignmentStyle {
731
- textAlign?: string;
732
- }
733
-
734
- type IconColor = 'black' | 'white' | 'color';
360
+ Note that when **disabling** the built-in submit button and using your own custom submit button, it is **required** to implement the `submit()` function in order to notify Universal Checkout of form submissions. <br />
361
+ Read more about the `submit()` function in the [Manual Form Submission](#manual-form-submission) section referenced below.
735
362
 
736
- ```
363
+ <br/>
737
364
 
738
- #### Input Style
365
+ When using your own custom submit button, it's important to use the following callbacks to ensure that your submit button is in the correct state and in sync with the checkout as your customers interact with it:
739
366
 
740
- ```typescript
741
- interface InputStyle {
742
- height?: number;
743
- paddingHorizontal?: number;
744
-
745
- background?: string;
746
- borderRadius?: number | string;
747
- boxShadow?: string;
748
-
749
- borderStyle?: string;
750
- borderColor?: number | string;
751
- borderWidth?: number | string;
752
-
753
- color?: string;
754
- fontFamily?: string;
755
- fontWeight?: string;
756
- fontSize?: string;
757
- fontSmoothing?: string;
758
- lineHeight?: string;
759
- }
760
- ```
367
+ ```javascript
368
+ const options = {
369
+ /* Other options ... */
761
370
 
762
- #### Success Screen
371
+ submitButton: {
372
+ useBuiltInButton: false, // Default to true
763
373
 
764
- By default, what happens after `onTokenizeSuccess` is called (and the Promise is resolved) depends on the payment method that the customer chooses. Some of them such as GoCardless requires us to display a screen that sums up the order to be displayed. Others, such as Card, does not require anything.
374
+ // Callback for receiving the submit button's visible state in the current scene
375
+ onVisible(isVisible, context: { currentSceneId }) {
376
+ // Show or hide your custom submit button
377
+ },
765
378
 
766
- However, it is good practice to show a success screen once the payment is validated. You can use the `successScreen` options to define which of the built-in success screens you want to show, or to disable the default behavior and display a custom success screen.
379
+ // Callback for receiving the submit button's disabled state in the current scene
380
+ onDisable(isDisabled, context: { currentSceneId }) {
381
+ // Disable or enable your custom submit button
382
+ },
767
383
 
768
- Note that when the `successScreen` is `undefined`, the `CHECK` success screen will be used by default. Also, when explicitly using `{ type: 'CHECK' }` a custom title can be defined.
384
+ // Callback for receiving the submit button's loading state in the current scene
385
+ onLoading(isLoading, context: { currentSceneId }) {
386
+ // Show your submit button in a loading state
387
+ },
769
388
 
770
- ```typescript
771
- enum SuccessScreenType {
772
- PAYMENT_METHOD = 'PAYMENT_METHOD',
773
- CHECK = 'CHECK',
774
- }
775
-
776
- export type CheckSuccessScreenOptions = {
777
- type: SuccessScreenType.CHECK;
778
- title: Label;
389
+ // Callback for receiving the submit button's content in the current scene
390
+ onContentChange(content, context: { currentSceneId }) {
391
+ // Set your submit button's content with either the content provided or your own custom content
392
+ },
393
+ },
779
394
  };
395
+ ```
780
396
 
781
- export type PaymentMethodSuccessScreenOptions = {
782
- type: SuccessScreenType.PAYMENT_METHOD;
783
- };
397
+ <br/>
784
398
 
785
- type SuccessScreenOptions =
786
- | /* No success screen will be displayed */ false
787
- | /* Show the default success screen of the payment method*/ undefined
788
- // Proposed success screens
789
- | CheckSuccessScreenOptions
790
- | PaymentMethodSuccessScreenOptions;
791
- ```
399
+ #### ⚙️ _Processing Indicator Options_
792
400
 
793
- ## Primer (Advanced usage)
401
+ Show a processing indicator overlay on top of the checkout when submitting a form:
794
402
 
795
- ### `Primer#render(options: PrimerClientRenderOptions): Promise<void>`
403
+ | option | Type | Description | Default | |
404
+ | ----------------------------- | ------- | -------------------------------------------------------------------------------- | ------- | -------- |
405
+ | `processingIndicator.visible` | Boolean | Choose whether a processing indicator overlay should be shown on form submission | true | optional |
796
406
 
797
- Securely render a credit card form or alternative payment method buttons.
407
+ <br/>
798
408
 
799
- ### `type PrimerClientRenderOptions`
409
+ #### ⚙️ _Error Message Options & Callbacks_
800
410
 
801
- ```typescript
802
- type PrimerClientRenderOptions {
803
- // Override the locale
804
- // By default translations will be provided for the browser's locale
805
- locale?: string;
806
-
807
- // Additional information relating to merchant operating address
808
- // [required for tax calculation via TaxJar]
809
- businessDetails?: {
810
- address: {
811
- countryCode: string;
812
- state: string;
813
- postalCode: string;
814
- city: string;
815
- addressLine1: string;
411
+ When Universal Checkout encounters errors processing payments, these errors will be shown to your users by default, below the submit button.
412
+
413
+ If you want to show your own error messages, you have the option to disable the default, built-in error messages:
414
+
415
+ | option | Type | Description | Default | |
416
+ | ----------------------- | ------- | ----------------------------------------------------------------- | ------- | -------- |
417
+ | `errorMessage.disabled` | Boolean | Choose whether to allow Universal Checkout to show error messages | false | optional |
418
+
419
+ <br/>
420
+
421
+ You can use the following callbacks to get notified when Universal Checkout intends to display an error message. By using these callbacks, you can respond with your own UI changes and avail a custom error message:
422
+
423
+ ```javascript
424
+ const options = {
425
+ /* Other options ... */
426
+
427
+ errorMessage: {
428
+ disabled: false, // Default to false
429
+
430
+ // A callback for when the error message should be displayed
431
+ onErrorMessageShow(message) {
432
+ // Choose to use provided message for own purposes
816
433
  },
817
- nexusAddresses: [
818
- {
819
- countryCode: string;
820
- state: string;
821
- postalCode: string;
822
- city: string;
823
- addressLine1: string;
824
- },
825
- ],
826
- },
827
434
 
828
- // Additional information relating to customer
829
- // [required for tax calculation via TaxJar]
830
- customerDetails?: {
831
- customerTaxId: string;
832
- shippingAddress: {
833
- countryCode: string;
834
- state: string;
835
- postalCode: string;
836
- city: string;
837
- addressLine1: string;
435
+ // A callback for when the error message should be hidden
436
+ onErrorMessageHide() {
437
+ // Update own UI accordingly
838
438
  },
839
439
  },
440
+ };
441
+ ```
840
442
 
841
- // A success callback, receives the payment method token.
842
- onTokenizeSuccess: (data: PaymentMethodToken) => void;
443
+ <br/>
843
444
 
844
- // A callback for when tokenization begins
845
- onTokenizeStart?: () => void;
445
+ #### ⚙️ _Success Screen Options_
846
446
 
847
- // A callback for when there is a tokenization error
848
- onTokenizeError?: (message: string) => void;
447
+ When the checkout is succefully complete, Universal Checkout displays a success scene with a default success message _"Your payment was successful!"_.
849
448
 
850
- // A callback for when tokenization ends
851
- onTokenizeEnd?: () => void;
449
+ Set the option `successScreen` to modify the behavior of the success scene.
852
450
 
853
- // A callback for when changes have been made to the totalAmount provided to the checkout
854
- onAmountChange?: (data: AmountChange) => void;
451
+ ```javascript
452
+ const options = {
453
+ /* Other options ... */
855
454
 
856
- // A callback for when changes totalAmount is being updated
857
- onAmountChanging?: (isChanging: boolean) => void;
455
+ // Remove the success screen
456
+ successScreen: false,
858
457
 
859
- // A callback for when an error occured while updating the totalAmount
860
- onAmountChangeError?: (message: PrimerError) => void;
458
+ // Change the message of the default success screen
459
+ successScreen: {
460
+ type: 'CHECK',
461
+ title: 'This is a custom success message!',
462
+ },
463
+ };
464
+ ```
861
465
 
862
- // A callback for receiving actions which can be used to update the client session
863
- onClientSessionActions?: (data: ClientSessionActionData) => Promise<{ clientToken: string } | false>;
466
+ ---
864
467
 
865
- // Configuration for a credit card form
866
- card?: {
867
- // The name of the cardholder
868
- // If a function is set, the function will be called when calling the `tokenize` function
869
- cardholderName?: string | () => string;
468
+ ### 🔨 **Advanced Options**
870
469
 
871
- // A callback for form metadata
872
- onChange?: (state: FormState) => void;
470
+ #### ⚙️ _Manual Payment Creation & Tokenization Lifecycle Callbacks_
873
471
 
874
- // A callback for extra card information (brand etc)
875
- onCardMetadata?: (meta: CardMetadata) => void;
472
+ By default, Universal Checkout will automatically create payments and manage their lifecycles on your behalf. The manual payment creation flow used in previous Web SDK versions is still supported.
876
473
 
877
- // Whether or not the form is disabled - this will prevent tokenization if it returns true
878
- disabled?: () => boolean;
474
+ Check our [Manual Payment Creation guide](https://primer.io/docs/accept-payments/advanced-checkout-configuration/manual).
879
475
 
880
- // A stylesheet to inject into each input element
881
- // For more information see the guide on styling
882
- css?: string;
476
+ <!--
883
477
 
884
- // A DOM selector for a button which will begin the tokenization
885
- submitButton: string;
478
+ By default, Universal Checkout will automatically create payments and manage their lifecycles on your behalf.
886
479
 
887
- // Credit card field configuration
888
- fields: {
889
- // Card number field configuration
890
- cardNumber: CreditCardFieldConfig;
891
- // Expiry Date field configuration
892
- expiryDate: CreditCardFieldConfig;
893
- // CVV field configuration
894
- cvv: CreditCardFieldConfig;
895
- };
896
- };
480
+ The manual payment creation flow used in previous Web SDK versions is still supported. To activate it, make sure to:
897
481
 
898
- // Configuration for alternative payment methods
899
- // The container property should be a DOM selector for a visible element n the page.
900
- applePay?: { container: string; };
901
- googlePay?: { container: string; };
902
- paypal?: { container: string; };
903
- }
904
- ```
482
+ - set `paymentHandling` to `MANUAL`
483
+ - implement `onTokenizeSuccess` and `onResumeSuccess`
905
484
 
906
- ### `type PaymentMethodToken`
485
+ ```javascript
486
+ const options = {
487
+ /* Other checkout options ... */
907
488
 
908
- A tokenized payment method. Use the token property to authorize transactions. The token object also contains some other metadata describing the payment method which it represents.
489
+ paymentHandling: 'MANUAL',
909
490
 
910
- ```typescript
911
- type PaymentMethodToken {
912
- // The token used to authorize transactions
913
- token: string;
914
- // The type of payment method which this token represents
915
- paymentMethodType: 'PAYMENT_CARD' | 'GOOGLE_PAY' | 'APPLE_PAY' | 'PAYPAL';
916
- // Additional data about the payment method
917
- paymentMethodData: object;
918
- }
919
- ```
491
+ async onTokenizeSuccess(paymentMethodTokenData, handler) {
492
+ // Send the Payment Method Token to your server
493
+ // to create a payment using Payments API
494
+ // const response = await createPayment(paymentMethodTokenData.token);
920
495
 
921
- ### `type FormState`
496
+ // Call `handler.handleFailure` to cancel the flow and display an error message
497
+ if (!response) {
498
+ return handler.handleFailure(
499
+ 'The payment failed. Please try with another payment method.',
500
+ );
501
+ }
922
502
 
923
- Form metadata
503
+ // If a new clientToken is available, call `handler.continueWithNewClientToken` to refresh the client session.
504
+ // The checkout will automatically perform the action required by the Workflow.
505
+ if (response.requiredAction.clientToken) {
506
+ return hander.continueWithNewClientToken(response.requiredAction.clientToken);
507
+ }
924
508
 
925
- ```typescript
926
- type FormState {
927
- // Whether any field is dirty
928
- dirty: boolean;
929
- // Whether any field was been touched
930
- touched: boolean;
931
- // Whether any field is active
932
- active: boolean;
933
- // Whether all fields are valid
934
- valid: boolean;
935
- // Whether the card form was submitted
936
- submitted: boolean;
937
- }
938
- ```
509
+ // Display the success screen
510
+ return hander.handleSuccess();
511
+ },
939
512
 
940
- ### `type CardMetadata`
513
+ async onResumeSuccess(resumeTokenData, handler) {
514
+ // Send the resume token to your server to resume the payment
515
+ // const response = await resumePayment(resumeTokenData.resumeToken);
941
516
 
942
- Additional Card information
517
+ // Call `handler.handlehandleFailureError` to cancel the flow and display an error message
518
+ if (!response) {
519
+ return handler.handleFailure(
520
+ 'The payment failed. Please try with another payment method.',
521
+ );
522
+ }
943
523
 
944
- ```typescript
945
- type CardMetadata {
946
- // The card type - 'visa' | 'mastercard' etc
947
- type?: string;
948
- // The possible types of the card given the current value
949
- possibleTypes: string[];
950
- }
524
+ // If a new clientToken is available, call `handler.continueWithNewClientToken` to refresh the client session.
525
+ // The checkout will automatically perform the action required by the Workflow
526
+ if (response.requiredAction.clientToken) {
527
+ return hander.continueWithNewClientToken(response.requiredAction.clientToken);
528
+ }
529
+
530
+ // Display the success screen
531
+ return hander.handleSuccess();
532
+ },
533
+ };
951
534
  ```
952
535
 
953
- ### `type CreditCardFieldConfig`
536
+ Additional optional callbacks are available:
954
537
 
955
- Configuration for credit card fields
538
+ ```javascript
539
+ const options = {
540
+ /* Other checkout options ... */
956
541
 
957
- ```typescript
958
- type CreditCardFieldConfig {
959
- // A DOM selector specifying where to render the input
960
- container: string;
961
- // Whether to append or prepend the input to the container element
962
- placement?: 'append' | 'prepend';
963
- // A placeholder to display when the input is empty
964
- placeholder?: string;
965
- // A callback which receives input metadata
966
- onChange: (data: { meta: FieldMetadata; }) => void;
967
- }
542
+ async onTokenizeShouldStart({ paymentMethodType }) {
543
+ // Return true if tokenization is allowed to start
544
+ return true;
545
+
546
+ // Return false if tokenization is not allowed to start
547
+ // This is likely to happen if the user has not properly filled in a form owned by you
548
+ return false;
549
+ },
550
+
551
+ onTokenizeDidNotStart(reason) {
552
+ // Tokenization did not start
553
+
554
+ if (reason === 'TOKENIZATION_DISABLED') {
555
+ // Tokenization has been disabled with `setTokenizationEnabled`
556
+ } else if (reason === 'TOKENIZATION_SHOULD_NOT_START') {
557
+ // Tokenization has been disabled by returning false in `onTokenizeShouldStart`
558
+ }
559
+ },
560
+
561
+ onTokenizeStart() {
562
+ // Tokenization has started
563
+ },
564
+
565
+ onResumeError(error) {
566
+ // Resuming has failed
567
+ },
568
+ };
968
569
  ```
969
570
 
970
- ### `type FieldMetadata`
571
+ -->
971
572
 
972
- Input metadata for a Credit card field
573
+ #### ⚙️ _Show the flow for a single payment method_
973
574
 
974
- ```typescript
975
- type FieldMetadata {
976
- // A validation error
977
- error?: string;
978
- // Whether or not the input contains valid information
979
- valid: boolean;
980
- // Whether or not the input is focussed
981
- active: boolean;
982
- // Whether or not the input's value has been changed
983
- dirty: boolean;
984
- // Whether or not the customer has focussed the field
985
- touched: boolean;
986
- // Whether or not the form has been submitted
987
- submitted: boolean;
988
- }
575
+ The payment methods featuring a dedicated screen allows you to directly display their flow. For that, make sure to:
576
+
577
+ - Set `uxFlow` to `SINGLE_PAYMENT_METHOD_CHECKOUT`
578
+ - Set `paymentMethod` to the payment method you want to display
579
+
580
+ ```javascript
581
+ const options = {
582
+ /* Other options ... */
583
+
584
+ uxFlow: 'SINGLE_PAYMENT_METHOD_CHECKOUT',
585
+ paymentMethod: 'PAYMENT_CARD',
586
+ };
989
587
  ```
990
588
 
991
- ---
589
+ Payment methods that supports this flow
992
590
 
993
- ### `Primer#threeDSecure: ThreeDSecure`
591
+ - Card: `PAYMENT_CARD`
592
+ - Klarna: `KLARNA`
593
+ - GoCardless: `GOCARDLESS`
994
594
 
995
- Primer 3DS verification API
595
+ #### ⚙️ _Customizable Payment Method Button options_
996
596
 
997
- ### `ThreeDSecure#verify(options: ThreeDSecureVerifyOptions): Promise<ThreeDSecureVerification>`
597
+ Some payment methods enables you to customize the payment method button.
998
598
 
999
- Perform a 3DS verification on a payment method token
599
+ | option | Type | Description | Default | |
600
+ | ------------ | ------ | -------------------------------------------------------------------------------- | ------------------- | -------- |
601
+ | `logoSrc` | String | Data URL representing the logo you want to display in the payment method button. | | required |
602
+ | `background` | String | Color of the background of the payment method button. | | required |
603
+ | `logoAlt` | String | Accessibility marker for the payment method button | | required |
604
+ | `text` | String | Label to display to the right of `logoSrc` | Only show `logoSrc` | optional |
1000
605
 
1001
- ### `type ThreeDSecureVerifyOptions`
606
+ Payment methods that supports this flow
1002
607
 
1003
- Options provided to 3DS verification
608
+ - Gift Cards with Mollie: `PAYMENT_CARD`
1004
609
 
1005
- ```typescript
1006
- type ThreeDSecureVerifyOptions {
1007
- // A Payment method token to perform 3DS verification for
1008
- token: string;
1009
-
1010
- // An element selector for the parent of the 3DS challenge UI
1011
- container: string;
1012
-
1013
- // A callback for when the 3DS challenge starts
1014
- onChallengeStart?: () => void;
1015
-
1016
- // A callback for when the 3DS challenge ends
1017
- onChallengeEnd?: () => void;
1018
-
1019
- // 3DS order details
1020
- order: {
1021
- // Your order ID
1022
- orderId: string;
1023
-
1024
- amount: {
1025
- // The sale amount
1026
- value: number | string;
1027
- // The alpha3 currency code of the sale
1028
- currency: string;
1029
- };
1030
-
1031
- // The customer's email address
1032
- email: string;
1033
-
1034
- billingAddress: {
1035
- // Billing first name
1036
- firstName: string;
1037
- // Billing last name
1038
- lastName: string;
1039
- // Street address
1040
- addressLine1: string;
1041
- // Extended street address
1042
- addressLine2?: string
1043
- // Extended street address
1044
- addressLine3?: string
1045
- // City or town
1046
- city: string;
1047
- // State, region or province
1048
- state?: string;
1049
- // The alpha2 country code of the address
1050
- countryCode: string;
1051
- // The postal or zip code
1052
- postalCode: string;
1053
- }
1054
- };
1055
- }
610
+ ## 🔧 &nbsp;<a id="checkout-methods"></a> Checkout Methods
611
+
612
+ Universal Checkout exposes some methods which can be called to perform some specific actions:
613
+
614
+ ### **Set Client Token**
615
+
616
+ When updating the client session, after the checkout has been initialized, you will receive a client token in the response returned from `PATCH /client-session`.
617
+
618
+ In order for the checkout to know that you have updated the client session, you will need to pass this new client token back to the checkout:
619
+
620
+ ```javascript
621
+ const universalCheckout = await Primer.showUniversalCheckout(
622
+ clientToken,
623
+ options,
624
+ );
625
+
626
+ // Pass the new client token to Universal Checkout by calling setClientToken
627
+ // This will result in Universal Checkout having access to the latest changes made to the client session
628
+ universalCheckout.setClientToken(clientToken);
1056
629
  ```
1057
630
 
1058
- ### `type ThreeDSecureVerification`
631
+ ### **Manual Form Submission**
1059
632
 
1060
- The result of a 3DS verification. If successful, a new token will be returned.
633
+ The checkout provides a method for manually calling submit. This is useful when using your own custom submit button.
1061
634
 
1062
- ```typescript
1063
- {
1064
- // The result status of the verification
1065
- status: 'AUTH_SUCCESS' | 'AUTH_FAILED' | 'SKIPPED';
1066
- // Optional error if something unexpected happened
1067
- error?: Error;
1068
- // Data object containing the new token
1069
- data?: PaymentMethodToken;
1070
- }
635
+ ```javascript
636
+ const universalCheckout = await Primer.showUniversalCheckout(
637
+ clientToken,
638
+ options,
639
+ );
640
+
641
+ const handleMySubmitButtonClick = () => {
642
+ // Forward all submit button clicks to the SDK
643
+ universalCheckout.submit();
644
+ };
645
+ ```
646
+
647
+ <br/>
648
+
649
+ ### **Disabling Tokenization and Payment Creation**
650
+
651
+ The checkout provides `setPaymentCreationEnabled` and `setTokenizationEnabled` to enable or disable tokenization and payment creation. Use this if you would like to prevent users from paying because your side of the checkout is not valid.
652
+
653
+ These two functions can be used interchangibly.
654
+
655
+ ```javascript
656
+ const universalCheckout = await Primer.showUniversalCheckout(
657
+ clientToken,
658
+ options,
659
+ );
660
+
661
+ // Disable payment creation
662
+ universalCheckout.setPaymentCreationEnabled(false);
663
+ universalCheckout.setTokenizationEnabled(false);
664
+
665
+ // Enable payment creation
666
+ universalCheckout.setPaymentCreationEnabled(true);
667
+ universalCheckout.setTokenizationEnabled(true);
1071
668
  ```