From cf8e77be0086598d2d680c95dc79be285b098557 Mon Sep 17 00:00:00 2001 From: Devin Michael Date: Wed, 21 Oct 2026 17:24:06 +0700 Subject: [PATCH 1/2] Document gateway three_ds_mode and Smart mode responses --- .../guides/payment-methods/bankcard.mdx | 11 +++- public/api/admin/2023-02-10.yaml | 50 +++++++++++++++++-- public/api/admin/2024-04-01.yaml | 50 +++++++++++++++++-- public/api/admin/unstable.yaml | 50 +++++++++++++++++-- 4 files changed, 151 insertions(+), 10 deletions(-) diff --git a/content/docs/admin-api/guides/payment-methods/bankcard.mdx b/content/docs/admin-api/guides/payment-methods/bankcard.mdx index 40c710c..0288e53 100644 --- a/content/docs/admin-api/guides/payment-methods/bankcard.mdx +++ b/content/docs/admin-api/guides/payment-methods/bankcard.mdx @@ -467,9 +467,18 @@ Older integrations load `iframe-v1.min.js` and call `Spreedly` directly. Replace 3DS2 payments are fully supported via the Admin API to process the customer through an authentication flow, with the final transaction information and results provided back to your application. -Your store must have a 3DS2-enabled gateway to process 3DS2 transactions. +Your store must have a 3DS2-enabled gateway to process 3DS2 transactions. A gateway is 3DS2-enabled when its `three_ds_mode` is `smart` or `always`. +### Smart mode gateways + +A gateway in `smart` mode decides per order whether to use 3DS. Orders with a billing address in the United States, Canada, Australia or New Zealand skip 3DS unless they score above the store's risk tolerance. All other orders use 3DS. See [3DS2 Payments](https://docs.nextcommerce.com/docs/features/payments/3ds2-payments#smart-mode) for the full rules. + +Send a `payment_return_url` on every order to a `smart` gateway, and handle both responses: + +- **3DS used:** the response carries a `payment_complete_url`. Continue with the redirect flow below. +- **3DS skipped:** the order is charged directly and the response is the created order, the same as a gateway with 3DS off. + ### API payment redirect flow diff --git a/public/api/admin/2023-02-10.yaml b/public/api/admin/2023-02-10.yaml index 005993c..09645b5 100644 --- a/public/api/admin/2023-02-10.yaml +++ b/public/api/admin/2023-02-10.yaml @@ -6240,9 +6240,10 @@ components: - integer - 'null' enable_3ds2: - description: Transactions are attempted with 3DS authentication. + description: Derived from `three_ds_mode`. True when the mode is `smart` or `always`. title: Enable 3D Secure Transactions type: boolean + readOnly: true gateway_groups: items: $ref: '#/components/schemas/PaymentGatewayGroup' @@ -6291,6 +6292,19 @@ components: type: - boolean - 'null' + three_ds_mode: + description: |- + 3DS mode for the gateway. + + * `off` - Off + * `smart` - Smart + * `always` - Always On + enum: + - 'off' + - smart + - always + title: 3DS Mode + type: string required: - card_types - currencies @@ -21676,6 +21690,7 @@ webhooks: is_default: false name: string re_attemp_intitial_charge: null + three_ds_mode: 'off' event_id: a7a26ff2-e851-45b6-9634-d595f45458b7 event_type: gateway.created object: gateway @@ -21732,9 +21747,10 @@ webhooks: minimum: 1 type: integer enable_3ds2: - description: Transactions are attempted with 3DS authentication. + description: Derived from `three_ds_mode`. True when the mode is `smart` or `always`. title: Enable 3D Secure Transactions type: boolean + readOnly: true gateway_groups: items: properties: @@ -21891,6 +21907,19 @@ webhooks: description: Reattempt soft declines with another gateway. title: Re-attempt declined initial charge attempts type: boolean + three_ds_mode: + description: |- + 3DS mode for the gateway. + + * `off` - Off + * `smart` - Smart + * `always` - Always On + enum: + - 'off' + - smart + - always + title: 3DS Mode + type: string required: - card_types - currencies @@ -22014,6 +22043,7 @@ webhooks: is_default: false name: string re_attemp_intitial_charge: null + three_ds_mode: 'off' event_id: a7a26ff2-e851-45b6-9634-d595f45458b7 event_type: gateway.updated object: gateway @@ -22070,9 +22100,10 @@ webhooks: minimum: 1 type: integer enable_3ds2: - description: Transactions are attempted with 3DS authentication. + description: Derived from `three_ds_mode`. True when the mode is `smart` or `always`. title: Enable 3D Secure Transactions type: boolean + readOnly: true gateway_groups: items: properties: @@ -22229,6 +22260,19 @@ webhooks: description: Reattempt soft declines with another gateway. title: Re-attempt declined initial charge attempts type: boolean + three_ds_mode: + description: |- + 3DS mode for the gateway. + + * `off` - Off + * `smart` - Smart + * `always` - Always On + enum: + - 'off' + - smart + - always + title: 3DS Mode + type: string required: - card_types - currencies diff --git a/public/api/admin/2024-04-01.yaml b/public/api/admin/2024-04-01.yaml index 6c7863f..87e54e6 100644 --- a/public/api/admin/2024-04-01.yaml +++ b/public/api/admin/2024-04-01.yaml @@ -6555,9 +6555,10 @@ components: - integer - 'null' enable_3ds2: - description: Transactions are attempted with 3DS authentication. + description: Derived from `three_ds_mode`. True when the mode is `smart` or `always`. title: Enable 3D Secure Transactions type: boolean + readOnly: true gateway_groups: items: $ref: '#/components/schemas/PaymentGatewayGroup' @@ -6606,6 +6607,19 @@ components: type: - boolean - 'null' + three_ds_mode: + description: |- + 3DS mode for the gateway. + + * `off` - Off + * `smart` - Smart + * `always` - Always On + enum: + - 'off' + - smart + - always + title: 3DS Mode + type: string required: - card_types - currencies @@ -27049,6 +27063,7 @@ webhooks: is_default: false name: string re_attemp_intitial_charge: null + three_ds_mode: 'off' event_id: a7a26ff2-e851-45b6-9634-d595f45458b7 event_type: gateway.created object: gateway @@ -27105,9 +27120,10 @@ webhooks: minimum: 1 type: integer enable_3ds2: - description: Transactions are attempted with 3DS authentication. + description: Derived from `three_ds_mode`. True when the mode is `smart` or `always`. title: Enable 3D Secure Transactions type: boolean + readOnly: true gateway_groups: items: properties: @@ -27264,6 +27280,19 @@ webhooks: description: Reattempt soft declines with another gateway. title: Re-attempt declined initial charge attempts type: boolean + three_ds_mode: + description: |- + 3DS mode for the gateway. + + * `off` - Off + * `smart` - Smart + * `always` - Always On + enum: + - 'off' + - smart + - always + title: 3DS Mode + type: string required: - card_types - currencies @@ -27387,6 +27416,7 @@ webhooks: is_default: false name: string re_attemp_intitial_charge: null + three_ds_mode: 'off' event_id: a7a26ff2-e851-45b6-9634-d595f45458b7 event_type: gateway.updated object: gateway @@ -27443,9 +27473,10 @@ webhooks: minimum: 1 type: integer enable_3ds2: - description: Transactions are attempted with 3DS authentication. + description: Derived from `three_ds_mode`. True when the mode is `smart` or `always`. title: Enable 3D Secure Transactions type: boolean + readOnly: true gateway_groups: items: properties: @@ -27602,6 +27633,19 @@ webhooks: description: Reattempt soft declines with another gateway. title: Re-attempt declined initial charge attempts type: boolean + three_ds_mode: + description: |- + 3DS mode for the gateway. + + * `off` - Off + * `smart` - Smart + * `always` - Always On + enum: + - 'off' + - smart + - always + title: 3DS Mode + type: string required: - card_types - currencies diff --git a/public/api/admin/unstable.yaml b/public/api/admin/unstable.yaml index ec3d4a6..4c6d551 100644 --- a/public/api/admin/unstable.yaml +++ b/public/api/admin/unstable.yaml @@ -6513,9 +6513,10 @@ components: - integer - 'null' enable_3ds2: - description: Transactions are attempted with 3DS authentication. + description: Derived from `three_ds_mode`. True when the mode is `smart` or `always`. title: Enable 3D Secure Transactions type: boolean + readOnly: true gateway_groups: items: $ref: '#/components/schemas/PaymentGatewayGroup' @@ -6564,6 +6565,19 @@ components: type: - boolean - 'null' + three_ds_mode: + description: |- + 3DS mode for the gateway. + + * `off` - Off + * `smart` - Smart + * `always` - Always On + enum: + - 'off' + - smart + - always + title: 3DS Mode + type: string required: - card_types - currencies @@ -26883,6 +26897,7 @@ webhooks: is_default: false name: string re_attemp_intitial_charge: null + three_ds_mode: 'off' event_id: a7a26ff2-e851-45b6-9634-d595f45458b7 event_type: gateway.created object: gateway @@ -26939,9 +26954,10 @@ webhooks: minimum: 1 type: integer enable_3ds2: - description: Transactions are attempted with 3DS authentication. + description: Derived from `three_ds_mode`. True when the mode is `smart` or `always`. title: Enable 3D Secure Transactions type: boolean + readOnly: true gateway_groups: items: properties: @@ -27098,6 +27114,19 @@ webhooks: description: Reattempt soft declines with another gateway. title: Re-attempt declined initial charge attempts type: boolean + three_ds_mode: + description: |- + 3DS mode for the gateway. + + * `off` - Off + * `smart` - Smart + * `always` - Always On + enum: + - 'off' + - smart + - always + title: 3DS Mode + type: string required: - card_types - currencies @@ -27221,6 +27250,7 @@ webhooks: is_default: false name: string re_attemp_intitial_charge: null + three_ds_mode: 'off' event_id: a7a26ff2-e851-45b6-9634-d595f45458b7 event_type: gateway.updated object: gateway @@ -27277,9 +27307,10 @@ webhooks: minimum: 1 type: integer enable_3ds2: - description: Transactions are attempted with 3DS authentication. + description: Derived from `three_ds_mode`. True when the mode is `smart` or `always`. title: Enable 3D Secure Transactions type: boolean + readOnly: true gateway_groups: items: properties: @@ -27436,6 +27467,19 @@ webhooks: description: Reattempt soft declines with another gateway. title: Re-attempt declined initial charge attempts type: boolean + three_ds_mode: + description: |- + 3DS mode for the gateway. + + * `off` - Off + * `smart` - Smart + * `always` - Always On + enum: + - 'off' + - smart + - always + title: 3DS Mode + type: string required: - card_types - currencies From a37f5d8bcf6b3dfcffcfcb5e08ee335cda6c9336 Mon Sep 17 00:00:00 2001 From: Devin Michael Date: Wed, 21 Oct 2026 17:34:40 +0700 Subject: [PATCH 2/2] Address review: required payment_return_url, quote enum values, drop webhook readOnly --- .../admin-api/guides/payment-methods/bankcard.mdx | 2 +- public/api/admin/2023-02-10.yaml | 14 ++++++-------- public/api/admin/2024-04-01.yaml | 14 ++++++-------- public/api/admin/unstable.yaml | 14 ++++++-------- 4 files changed, 19 insertions(+), 25 deletions(-) diff --git a/content/docs/admin-api/guides/payment-methods/bankcard.mdx b/content/docs/admin-api/guides/payment-methods/bankcard.mdx index 0288e53..4b423b7 100644 --- a/content/docs/admin-api/guides/payment-methods/bankcard.mdx +++ b/content/docs/admin-api/guides/payment-methods/bankcard.mdx @@ -474,7 +474,7 @@ Your store must have a 3DS2-enabled gateway to process 3DS2 transactions. A gate A gateway in `smart` mode decides per order whether to use 3DS. Orders with a billing address in the United States, Canada, Australia or New Zealand skip 3DS unless they score above the store's risk tolerance. All other orders use 3DS. See [3DS2 Payments](https://docs.nextcommerce.com/docs/features/payments/3ds2-payments#smart-mode) for the full rules. -Send a `payment_return_url` on every order to a `smart` gateway, and handle both responses: +`payment_return_url` is required on every order to a `smart` gateway, including orders that end up skipping 3DS, because the gateway decides per order. Handle both responses: - **3DS used:** the response carries a `payment_complete_url`. Continue with the redirect flow below. - **3DS skipped:** the order is charged directly and the response is the created order, the same as a gateway with 3DS off. diff --git a/public/api/admin/2023-02-10.yaml b/public/api/admin/2023-02-10.yaml index 09645b5..8b48aec 100644 --- a/public/api/admin/2023-02-10.yaml +++ b/public/api/admin/2023-02-10.yaml @@ -6301,8 +6301,8 @@ components: * `always` - Always On enum: - 'off' - - smart - - always + - 'smart' + - 'always' title: 3DS Mode type: string required: @@ -21750,7 +21750,6 @@ webhooks: description: Derived from `three_ds_mode`. True when the mode is `smart` or `always`. title: Enable 3D Secure Transactions type: boolean - readOnly: true gateway_groups: items: properties: @@ -21916,8 +21915,8 @@ webhooks: * `always` - Always On enum: - 'off' - - smart - - always + - 'smart' + - 'always' title: 3DS Mode type: string required: @@ -22103,7 +22102,6 @@ webhooks: description: Derived from `three_ds_mode`. True when the mode is `smart` or `always`. title: Enable 3D Secure Transactions type: boolean - readOnly: true gateway_groups: items: properties: @@ -22269,8 +22267,8 @@ webhooks: * `always` - Always On enum: - 'off' - - smart - - always + - 'smart' + - 'always' title: 3DS Mode type: string required: diff --git a/public/api/admin/2024-04-01.yaml b/public/api/admin/2024-04-01.yaml index 87e54e6..72024e6 100644 --- a/public/api/admin/2024-04-01.yaml +++ b/public/api/admin/2024-04-01.yaml @@ -6616,8 +6616,8 @@ components: * `always` - Always On enum: - 'off' - - smart - - always + - 'smart' + - 'always' title: 3DS Mode type: string required: @@ -27123,7 +27123,6 @@ webhooks: description: Derived from `three_ds_mode`. True when the mode is `smart` or `always`. title: Enable 3D Secure Transactions type: boolean - readOnly: true gateway_groups: items: properties: @@ -27289,8 +27288,8 @@ webhooks: * `always` - Always On enum: - 'off' - - smart - - always + - 'smart' + - 'always' title: 3DS Mode type: string required: @@ -27476,7 +27475,6 @@ webhooks: description: Derived from `three_ds_mode`. True when the mode is `smart` or `always`. title: Enable 3D Secure Transactions type: boolean - readOnly: true gateway_groups: items: properties: @@ -27642,8 +27640,8 @@ webhooks: * `always` - Always On enum: - 'off' - - smart - - always + - 'smart' + - 'always' title: 3DS Mode type: string required: diff --git a/public/api/admin/unstable.yaml b/public/api/admin/unstable.yaml index 4c6d551..a7e5f72 100644 --- a/public/api/admin/unstable.yaml +++ b/public/api/admin/unstable.yaml @@ -6574,8 +6574,8 @@ components: * `always` - Always On enum: - 'off' - - smart - - always + - 'smart' + - 'always' title: 3DS Mode type: string required: @@ -26957,7 +26957,6 @@ webhooks: description: Derived from `three_ds_mode`. True when the mode is `smart` or `always`. title: Enable 3D Secure Transactions type: boolean - readOnly: true gateway_groups: items: properties: @@ -27123,8 +27122,8 @@ webhooks: * `always` - Always On enum: - 'off' - - smart - - always + - 'smart' + - 'always' title: 3DS Mode type: string required: @@ -27310,7 +27309,6 @@ webhooks: description: Derived from `three_ds_mode`. True when the mode is `smart` or `always`. title: Enable 3D Secure Transactions type: boolean - readOnly: true gateway_groups: items: properties: @@ -27476,8 +27474,8 @@ webhooks: * `always` - Always On enum: - 'off' - - smart - - always + - 'smart' + - 'always' title: 3DS Mode type: string required: