@gopaycz/gopay-js-sdk 1.6.6 → 1.8.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/CHANGELOG.md +53 -0
- package/README.md +100 -98
- package/dist/index.cjs +213 -85
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +27 -5
- package/dist/index.d.ts +27 -5
- package/dist/index.js +211 -85
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/src/index.ts +6 -1
- package/src/modules/payments/payments.module.ts +45 -2
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,56 @@
|
|
|
1
|
+
# [1.8.0](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/compare/1.7.1...1.8.0) (2026-07-08)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Bug Fixes
|
|
5
|
+
|
|
6
|
+
* suppress js-yaml CVE-1121860 pending age-gate (audit) GPOMA-2398 ([2cc80b6](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/2cc80b69082d3b851b17cc52da8a7a76a8e7eb41))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
### Features
|
|
10
|
+
|
|
11
|
+
* **ci:** introduce internal README and stop mirroring it to GitHub GPOMA-2398 ([11c0ff9](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/11c0ff99c1e56f867c37fd2c67b9e9328ac6ec08))
|
|
12
|
+
|
|
13
|
+
## [1.7.1](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/compare/1.7.0...1.7.1) (2026-06-29)
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
### Bug Fixes
|
|
17
|
+
|
|
18
|
+
* add fancy npm badges GPOMA-2375 ([9a8f3a7](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/9a8f3a76661d069a5b23791759062e3b39a8b21a))
|
|
19
|
+
|
|
20
|
+
# [1.7.0](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/compare/1.6.7...1.7.0) (2026-06-29)
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
### Bug Fixes
|
|
24
|
+
|
|
25
|
+
* use api from production link GPOMA-2375 ([51e1574](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/51e157458f0f54a18a1460f4754df3c5103a560f))
|
|
26
|
+
* **audit:** suppress git-raw-commits deprecation GPOMA-2375 ([35f2379](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/35f237916d8581427bb9b358ffa20e0c07e9fc82))
|
|
27
|
+
* **browser-sdk:** guard attachPayment() against re-call while card form mounted D1 GPOMA-2375 ([41fa86d](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/41fa86d19957c6e1b0c94c491f2dfb8db438330e))
|
|
28
|
+
* **cards,polling,wallets,http:** code bugs B1 B2 B3 B6 D3 GPOMA-2375 ([55228e3](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/55228e3c5e0de30fa0934fddb31ff53ef6f2b5a7))
|
|
29
|
+
* **cards:** use cardFormSessionActive flag to close race in isCardFormMounted (D1) GPOMA-2375 ([b1d85c5](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/b1d85c5531b512c2d7160c693fe22c92e40d1cf9))
|
|
30
|
+
* **polling:** forward abort signal to per-poll client.get() GPOMA-2375 ([5d36270](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/5d36270589fe92e6b690276e47dd474bf99d58e8))
|
|
31
|
+
* update push instructions GPOMA-2375 ([160ce7e](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/160ce7e98c1143abe34e081153cc5bec7c418027))
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
### Features
|
|
35
|
+
|
|
36
|
+
* **api:** wire AbortSignal through public payment methods (D4) GPOMA-2375 ([a23bd08](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/a23bd08e6b99fa89901a7813f581adfdfae91a2d))
|
|
37
|
+
* **errors,polling:** attach chargeState to CHARGE_FAILED error for catch callers D2 GPOMA-2375 ([26f1f38](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/26f1f38470c47b008684de17eb742f0c820ba1a3))
|
|
38
|
+
* **http:** add AbortSignal to RequestOptions and thread into all fetch calls D4 GPOMA-2375 ([81c2721](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/81c27211fabefc5de47b7211aad9b73403bc5755))
|
|
39
|
+
* **payments:** add awaitPaymentStatus() polling helper for QR and bank-transfer flows M1 GPOMA-2375 ([10b447a](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/10b447a8202607afc9b737aa44f4ae7ed8a1fce3))
|
|
40
|
+
* **scopes:** export GoPayScopes constants and combineScopes helper M2 GPOMA-2375 ([74b94f8](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/74b94f84e2c815789c4842d088e7ddc43eba8e64))
|
|
41
|
+
|
|
42
|
+
## [1.6.7](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/compare/1.6.6...1.6.7) (2026-06-24)
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
### Bug Fixes
|
|
46
|
+
|
|
47
|
+
* clarify theming link GPOMA-2364 ([dca521f](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/dca521f92fce78714d5ae5ee0ae2052f75f160f4))
|
|
48
|
+
* rename env filename GPOMA-2364 ([5eed047](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/5eed047b701a3350370c6da2467bdcb2bbacf356))
|
|
49
|
+
* rename remaining GP_GW_JS_SDK_* refs and make BASE_URL optional in e2e config GPOMA-2364 ([4e4774b](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/4e4774b1a8e4f5948f8674e3805568ba9aa4b445))
|
|
50
|
+
* run tests on local node GPOMA-2364 ([a54e7fa](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/a54e7facda750dcc423fdca0ae7142b93cc9344d))
|
|
51
|
+
* update env example GPOMA-2364 ([fe2a3ea](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/fe2a3eaa86ab5ef2c77ed3e2016f3069b5d5ff2e))
|
|
52
|
+
* update README env var names to GOPAY_PAYMENTS_V4_ prefix GPOMA-2364 ([cb3a07a](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/commits/cb3a07a056a10fd3d90f0d20fa147e7ddfb4a34f))
|
|
53
|
+
|
|
1
54
|
## [1.6.6](https://bitbucket.org/gp-gopay/gp-gw-js-sdk/compare/1.6.5...1.6.6) (2026-06-17)
|
|
2
55
|
|
|
3
56
|
|
package/README.md
CHANGED
|
@@ -1,6 +1,11 @@
|
|
|
1
1
|
# @gopaycz/gopay-js-sdk
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
[](https://www.npmjs.com/package/@gopaycz/gopay-js-sdk)
|
|
4
|
+
[](https://sonarcloud.io/summary/new_code?id=gp-gopay_gp-gw-js-sdk)
|
|
5
|
+
[](https://sonarcloud.io/summary/new_code?id=gp-gopay_gp-gw-js-sdk)
|
|
6
|
+
[](https://opensource.org/licenses/MIT)
|
|
7
|
+
|
|
8
|
+
GoPay JavaScript SDK for server-side use (Node.js) — wraps the new [GoPay Payments API v4](https://api-docs.gopay.com/).
|
|
4
9
|
|
|
5
10
|
> **Building a browser integration?** Use [`@gopaycz/gopay-js-sdk-browser`](../browser-sdk/README.md) — it handles in-browser card encryption, direct-charge flows, and exposes an IIFE bundle for CDN use.
|
|
6
11
|
|
|
@@ -50,14 +55,15 @@ const payment = await sdk.createPayment('YOUR_GOID', {
|
|
|
50
55
|
Once the customer completes the payment flow and returns to your site, charge the payment using the instrument they provided:
|
|
51
56
|
|
|
52
57
|
```ts
|
|
53
|
-
// Card token
|
|
58
|
+
// Card token: obtained via the browser SDK card form (see @gopaycz/gopay-js-sdk-browser)
|
|
59
|
+
// and forwarded to your server after tokenization via sdk.tokenizeEncryptedCard()
|
|
54
60
|
const charge = await sdk.chargePayment(payment.id, {
|
|
55
61
|
payment_instrument: {
|
|
56
62
|
payment_instrument: 'PAYMENT_CARD',
|
|
57
63
|
input: {
|
|
58
64
|
input_type: 'CARD_TOKEN',
|
|
59
65
|
card_token: cardToken.token,
|
|
60
|
-
|
|
66
|
+
challenge_preference: 'AUTO',
|
|
61
67
|
},
|
|
62
68
|
},
|
|
63
69
|
});
|
|
@@ -82,7 +88,7 @@ The SDK uses OAuth2. **Client credentials (`client_id` / `client_secret`) must n
|
|
|
82
88
|
Your backend holds the credentials. Call `authenticate()` once on startup — the SDK stores the token and refreshes it transparently before expiry:
|
|
83
89
|
|
|
84
90
|
```ts
|
|
85
|
-
import { createGoPaySDK } from '@gopaycz/gopay-js-sdk';
|
|
91
|
+
import { createGoPaySDK, GoPayScopes } from '@gopaycz/gopay-js-sdk';
|
|
86
92
|
|
|
87
93
|
const sdk = createGoPaySDK({ environment: 'production' });
|
|
88
94
|
|
|
@@ -90,13 +96,27 @@ await sdk.authenticate({
|
|
|
90
96
|
grant_type: 'client_credentials',
|
|
91
97
|
client_id: process.env.GOPAY_CLIENT_ID,
|
|
92
98
|
client_secret: process.env.GOPAY_CLIENT_SECRET,
|
|
93
|
-
scope: '
|
|
99
|
+
scope: GoPayScopes.PAYMENT_WRITE + ' ' + GoPayScopes.PAYMENT_READ,
|
|
100
|
+
// or: scope: combineScopes(GoPayScopes.PAYMENT_WRITE, GoPayScopes.PAYMENT_READ)
|
|
101
|
+
// or just a plain string: scope: 'payment:write payment:read'
|
|
94
102
|
});
|
|
95
103
|
|
|
96
104
|
// All subsequent calls attach the Bearer token automatically.
|
|
97
105
|
const payment = await sdk.createPayment(goid, params);
|
|
98
106
|
```
|
|
99
107
|
|
|
108
|
+
### Scopes reference
|
|
109
|
+
|
|
110
|
+
| Scope | Constant | Used by |
|
|
111
|
+
|---|---|---|
|
|
112
|
+
| `payment:write` | `GoPayScopes.PAYMENT_WRITE` | `createPayment`, `chargePayment`, `refundPayment`, recurrences, payment links |
|
|
113
|
+
| `payment:read` | `GoPayScopes.PAYMENT_READ` | `getPaymentStatus`, `getChargeState`, `listRefunds`, `getRefund`, recurrence status |
|
|
114
|
+
| `card:write` | `GoPayScopes.CARD_WRITE` | `getBrowserKeys()` — allows the browser SDK to present the card form |
|
|
115
|
+
| `card:read` | `GoPayScopes.CARD_READ` | `getCardDetails`, `deleteCard` |
|
|
116
|
+
| `payment:charge` | `GoPayScopes.PAYMENT_CHARGE` | Browser SDK only (`attachPayment` / `payment_credentials` grant) |
|
|
117
|
+
|
|
118
|
+
For `getBrowserKeys()` to work, include `card:write` in your server-side `authenticate()` call. `shareableKey` must also be set in the SDK config (see [Browser keys](#browser-keys) below). Include `payment:write` (and any other scopes) as needed for the rest of your integration.
|
|
119
|
+
|
|
100
120
|
---
|
|
101
121
|
|
|
102
122
|
## Configuration
|
|
@@ -153,6 +173,28 @@ The one exception is `startApplePaySession`: it returns `void` instead of a Prom
|
|
|
153
173
|
| `isAuthenticated()` | Returns `true` if a token is currently stored. Does not check expiry — expired tokens are refreshed transparently on the next API call. |
|
|
154
174
|
| `logout()` | Clear all stored tokens and credentials. All subsequent API calls will throw until the SDK is re-authenticated. |
|
|
155
175
|
|
|
176
|
+
#### Browser keys
|
|
177
|
+
|
|
178
|
+
`getBrowserKeys()` returns `{ shareable_key, client_id }` — pass both to the browser SDK via your own API endpoint.
|
|
179
|
+
|
|
180
|
+
**Prerequisites:**
|
|
181
|
+
- The `shareableKey` option must be set when creating the SDK:
|
|
182
|
+
```ts
|
|
183
|
+
const sdk = createGoPaySDK({
|
|
184
|
+
environment: 'production',
|
|
185
|
+
shareableKey: process.env.GOPAY_SHAREABLE_KEY, // issued in GoPay admin alongside client_id
|
|
186
|
+
});
|
|
187
|
+
```
|
|
188
|
+
- The token scope must include `card:write` (obtain `shareableKey` from the GoPay admin portal):
|
|
189
|
+
```ts
|
|
190
|
+
await sdk.authenticate({
|
|
191
|
+
...,
|
|
192
|
+
scope: 'payment:write payment:read card:write',
|
|
193
|
+
});
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
Throws `AUTH_CREDENTIALS_MISSING` if either prerequisite is missing.
|
|
197
|
+
|
|
156
198
|
### Payments
|
|
157
199
|
|
|
158
200
|
| Method | Description |
|
|
@@ -313,127 +355,72 @@ document.body.appendChild(img);
|
|
|
313
355
|
|
|
314
356
|
### Cards
|
|
315
357
|
|
|
358
|
+
> **SDK boundary:** card data encryption and the card form UI live in the **browser SDK** ([`@gopaycz/gopay-js-sdk-browser`](../browser-sdk/README.md)), not here. The browser encrypts the card inside a GoPay-hosted iframe and returns an `encryptedPayload`; your server calls `tokenizeEncryptedCard` to convert it to a card token, then charges the payment. Raw card data never touches your server or this SDK.
|
|
359
|
+
|
|
316
360
|
| Method | Description |
|
|
317
361
|
|---|---|
|
|
318
|
-
| `
|
|
319
|
-
| `getCardDetails(cardId)` | Retrieve details of a stored permanent card token (`GET /cards/tokens/{cardId}`). Returns masked PAN, expiry, scheme, fingerprint, and the reusable token. Requires
|
|
320
|
-
| `deleteCard(cardId)` | Delete a stored permanent card token (`DELETE /cards/tokens/{cardId}`). Returns `void`. |
|
|
321
|
-
|
|
322
|
-
#### `mountCardForm` options
|
|
323
|
-
|
|
324
|
-
| Option | Type | Default | Description |
|
|
325
|
-
|---|---|---|---|
|
|
326
|
-
| `theme` | `CardFormTheme` | `DEFAULT_CARD_FORM_THEME` | Visual theme (colors, font sizes, spacing, button styles). All fields are optional — the iframe applies built-in defaults for any omitted field. |
|
|
327
|
-
| `locale` | `string` | `navigator.language` | BCP 47 language tag for form labels and placeholders. The region subtag is ignored (`'cs-CZ'` → `'cs'`). Unknown locales fall back to English. Supported: `bg` `cs` `de` `en` `es` `et` `fr` `hr` `hu` `it` `lt` `lv` `nl` `pl` `pt` `ro` `ru` `sk` `sl` `uk`. |
|
|
328
|
-
| `submitMode` | `'internal' \| 'external'` | `'internal'` | `'internal'` — the iframe renders its own submit button. `'external'` — the iframe hides the button; the parent controls submission via `cardForm.submit()` and receives validity changes via `onValidityChange`. |
|
|
329
|
-
| `permanent` | `boolean` | `false` | When `true`, a permanent (reusable) card token is created that can be charged again for future payments. When `false` (default), a single-use token is created. |
|
|
330
|
-
| `onValidityChange` | `(isValid: boolean) => void` | — | Called whenever the overall form validity changes in external submit mode. Use this to enable/disable your external submit button. |
|
|
331
|
-
|
|
332
|
-
> **Send theme and locale at init time.** Both options are applied before the form is first painted, avoiding a flash of unstyled content. Use `cardForm.setTheme()` and `cardForm.setLocale()` on the returned controller if you need to update them after mounting.
|
|
333
|
-
|
|
334
|
-
`CardFormTheme` is fully typed — hover in your editor to see every available field. Notable fields:
|
|
362
|
+
| `tokenizeEncryptedCard(encryptedPayload)` | Convert the encrypted payload returned by the browser SDK into a card token (`POST /cards/tokens`). Requires `card:write` scope. Returns `{ token, card_id? }`. |
|
|
363
|
+
| `getCardDetails(cardId)` | Retrieve details of a stored permanent card token (`GET /cards/tokens/{cardId}`). Returns masked PAN, expiry, scheme, fingerprint, and the reusable token. Requires `card:read` scope. |
|
|
364
|
+
| `deleteCard(cardId)` | Delete a stored permanent card token (`DELETE /cards/tokens/{cardId}`). Returns `void`. Requires `card:read` scope. |
|
|
335
365
|
|
|
336
|
-
|
|
337
|
-
|---|---|---|---|
|
|
338
|
-
| `fontFamily` | `string` | `system-ui, sans-serif` | CSS font-family stack applied to all form text (labels, inputs, errors, submit button). Use system font stacks — e.g. `"Inter, system-ui, sans-serif"` — to match your page without loading external fonts. |
|
|
366
|
+
### Flow A — server-side card charge
|
|
339
367
|
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
Theme presets are exported from the package:
|
|
368
|
+
The browser encrypts the card; your server tokenizes and charges. This is the recommended flow when your server handles the charge (e.g. to save the token for future use).
|
|
343
369
|
|
|
344
370
|
```ts
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
DEFAULT_CARD_FORM_THEME,
|
|
348
|
-
DARK_CARD_FORM_THEME,
|
|
349
|
-
} from '@gopaycz/gopay-js-sdk';
|
|
350
|
-
|
|
351
|
-
// Default theme, locale from navigator.language (options can be omitted entirely)
|
|
352
|
-
const cardForm = await sdk.mountCardForm(container);
|
|
353
|
-
const cardToken = await cardForm.result;
|
|
354
|
-
|
|
355
|
-
// Dark theme with Czech locale
|
|
356
|
-
const cardForm = await sdk.mountCardForm(container, {
|
|
357
|
-
theme: DARK_CARD_FORM_THEME,
|
|
358
|
-
locale: 'cs',
|
|
359
|
-
});
|
|
360
|
-
const cardToken = await cardForm.result;
|
|
361
|
-
|
|
362
|
-
// Custom theme — override individual fields, keep the rest as defaults
|
|
363
|
-
const cardForm = await sdk.mountCardForm(container, {
|
|
364
|
-
theme: { ...DEFAULT_CARD_FORM_THEME, submitBackgroundColor: '#your-brand-color' },
|
|
365
|
-
});
|
|
366
|
-
|
|
367
|
-
// Update theme or locale at runtime (e.g. user toggles dark mode or language)
|
|
368
|
-
darkModeToggle.addEventListener('change', () => cardForm.setTheme(DARK_CARD_FORM_THEME));
|
|
369
|
-
langSelect.addEventListener('change', e => cardForm.setLocale(e.target.value));
|
|
371
|
+
// ── Browser (using @gopaycz/gopay-js-sdk-browser) ──────────────────────────
|
|
372
|
+
import { createGoPayBrowserSDK, collectBrowserData } from '@gopaycz/gopay-js-sdk-browser';
|
|
370
373
|
|
|
371
|
-
const
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
#### External submit button
|
|
375
|
-
|
|
376
|
-
Use `submitMode: 'external'` when you want the submit button to live outside the iframe — for example to match your own checkout UI. The iframe hides its built-in button, reports validity changes via `onValidityChange`, and waits for `cardForm.submit()` to trigger encryption.
|
|
374
|
+
const browserSdk = createGoPayBrowserSDK({ environment: 'production', shareableKey, clientId });
|
|
375
|
+
const controller = await browserSdk.mountCardForm(container, { flow: 'return-payload' });
|
|
376
|
+
const { encryptedPayload } = await controller.result;
|
|
377
377
|
|
|
378
|
-
|
|
379
|
-
const
|
|
378
|
+
// Collect browser data for 3DS — must be done in the browser
|
|
379
|
+
const browserData = collectBrowserData();
|
|
380
380
|
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
},
|
|
381
|
+
// Forward both to your server endpoint
|
|
382
|
+
await fetch('/api/charge', {
|
|
383
|
+
method: 'POST',
|
|
384
|
+
headers: { 'Content-Type': 'application/json' },
|
|
385
|
+
body: JSON.stringify({ paymentId, encryptedPayload, browserData }),
|
|
387
386
|
});
|
|
388
387
|
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
});
|
|
392
|
-
|
|
393
|
-
// Await the result exactly the same as in internal submit.
|
|
394
|
-
const cardToken = await cardForm.result;
|
|
395
|
-
```
|
|
396
|
-
|
|
397
|
-
`cardForm.isValid` is also available as a synchronous getter in case you need to read the current validity state imperatively (e.g. inside a click handler before calling `submit()`).
|
|
398
|
-
|
|
399
|
-
> Calling `submit()` in internal submit mode throws a `GoPaySDKError`. Calling it after the form completes or is unmounted is a no-op.
|
|
400
|
-
|
|
401
|
-
### Card Pay
|
|
388
|
+
// ── Server (using @gopaycz/gopay-js-sdk) ───────────────────────────────────
|
|
389
|
+
import { createGoPaySDK } from '@gopaycz/gopay-js-sdk';
|
|
402
390
|
|
|
403
|
-
|
|
391
|
+
const sdk = createGoPaySDK({ environment: 'production' });
|
|
392
|
+
await sdk.authenticate({ ..., scope: 'payment:write payment:read card:write' });
|
|
404
393
|
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
const payment = await sdk.createPayment(goid, params);
|
|
394
|
+
// Handler for POST /api/charge
|
|
395
|
+
const { encryptedPayload, paymentId, browserData } = req.body;
|
|
408
396
|
|
|
409
|
-
//
|
|
410
|
-
|
|
411
|
-
// and calls POST /cards/tokens automatically.
|
|
412
|
-
const container = document.getElementById('card-form-container');
|
|
413
|
-
const cardForm = await sdk.mountCardForm(container);
|
|
414
|
-
const cardToken = await cardForm.result;
|
|
397
|
+
// 1. Convert encrypted payload to a card token
|
|
398
|
+
const cardToken = await sdk.tokenizeEncryptedCard(encryptedPayload);
|
|
415
399
|
|
|
416
|
-
//
|
|
417
|
-
const charge = await sdk.chargePayment(
|
|
400
|
+
// 2. Charge the payment — always forward browserData from the browser for 3DS
|
|
401
|
+
const charge = await sdk.chargePayment(paymentId, {
|
|
418
402
|
payment_instrument: {
|
|
419
403
|
payment_instrument: 'PAYMENT_CARD',
|
|
420
404
|
input: {
|
|
421
405
|
input_type: 'CARD_TOKEN',
|
|
422
406
|
card_token: cardToken.token,
|
|
423
|
-
|
|
407
|
+
challenge_preference: 'AUTO',
|
|
408
|
+
browser_data: browserData, // required for 3DS — do not omit
|
|
424
409
|
},
|
|
425
410
|
},
|
|
426
411
|
});
|
|
427
412
|
|
|
428
413
|
if (charge.action?.redirect_url) {
|
|
429
|
-
// 3DS authentication required — redirect the customer
|
|
430
|
-
|
|
414
|
+
// 3DS authentication required — redirect the customer
|
|
415
|
+
res.json({ redirectUrl: charge.action.redirect_url });
|
|
431
416
|
}
|
|
432
417
|
```
|
|
433
418
|
|
|
419
|
+
> **`browser_data` is required for 3DS.** The server SDK does not auto-collect it (only the browser SDK can). Always forward it from the browser via `collectBrowserData()`. Without it, 3DS context is absent and approval rates degrade.
|
|
420
|
+
|
|
434
421
|
### Saved cards
|
|
435
422
|
|
|
436
|
-
|
|
423
|
+
To save a card for future payments, pass `permanent: true` to `mountCardForm` in the browser SDK. The resulting `cardToken.card_id` can be stored and used to charge again without re-entering card details:
|
|
437
424
|
|
|
438
425
|
```ts
|
|
439
426
|
// Retrieve details of a stored card (masked PAN, expiry, scheme, etc.)
|
|
@@ -452,8 +439,6 @@ const charge = await sdk.chargePayment(payment.id, {
|
|
|
452
439
|
await sdk.deleteCard(card.card_id);
|
|
453
440
|
```
|
|
454
441
|
|
|
455
|
-
`GET /encryption/public-key` and the JWE construction it enables are **intentionally not part of this SDK's API surface**.
|
|
456
|
-
|
|
457
442
|
---
|
|
458
443
|
|
|
459
444
|
### Recurrences
|
|
@@ -600,6 +585,23 @@ try {
|
|
|
600
585
|
| `status` | `number` | HTTP status code (e.g. `401`, `422`). |
|
|
601
586
|
| `body` | `unknown` | Parsed JSON response body, or raw text if JSON parsing failed. |
|
|
602
587
|
|
|
588
|
+
A 422 error from `chargePayment` with an invalid amount looks like:
|
|
589
|
+
|
|
590
|
+
```json
|
|
591
|
+
{
|
|
592
|
+
"date_time": "2024-03-15T14:22:00.000+0100",
|
|
593
|
+
"error_code": 400,
|
|
594
|
+
"error_name": "PAYMENT_VALIDATION_ERROR",
|
|
595
|
+
"message": [
|
|
596
|
+
{
|
|
597
|
+
"field": "amount",
|
|
598
|
+
"message": "INVALID",
|
|
599
|
+
"description": "Value 0 is out of allowed range [1, 99999999]"
|
|
600
|
+
}
|
|
601
|
+
]
|
|
602
|
+
}
|
|
603
|
+
```
|
|
604
|
+
|
|
603
605
|
### Centralised error handling with `onError`
|
|
604
606
|
|
|
605
607
|
Pass an `onError` callback to the SDK config to intercept every error in one place — useful for logging or alerting — without replacing per-call `catch` blocks:
|