diff --git a/.cspell/custom-words.txt b/.cspell/custom-words.txt index 9490b8f05..ec06d4955 100644 --- a/.cspell/custom-words.txt +++ b/.cspell/custom-words.txt @@ -107,3 +107,10 @@ zapatillas yml jwks keyid +CAVV +Cybersource +MDES +ntoken +TAVV +TRID +YFAAAAAAAAAAA diff --git a/docs/specification/card-network-token.md b/docs/specification/card-network-token.md new file mode 100644 index 000000000..074abe98f --- /dev/null +++ b/docs/specification/card-network-token.md @@ -0,0 +1,173 @@ + + +# Card Network Token Credential + +## Overview + +The card network token credential type enables platforms to present card +network tokens (Visa VTS, Mastercard MDES, Amex Token Service) directly as +payment credentials in checkout sessions. Network tokens are opaque +credentials issued by card networks that replace the primary account number +(PAN) with a domain-restricted, cryptogram-protected token. + +**Key features:** + +- Present pre-provisioned network tokens directly at checkout +- Eliminate CVV collection (cryptogram structurally replaces CVC) +- Reduce PCI DSS compliance scope compared to handling raw card data +- Support all major card networks (Visa, Mastercard, Amex, Discover, JCB) + +**Dependencies:** + +- Checkout Capability +- Payment Handler Guide + +## Credential Schema + +### `card_network_token_credential.json` + +The credential extends `payment_credential.json` via `allOf`: + +| Field | Type | Required | Description | +|----------------------|---------|----------|------------------------------------------------------------------| +| `type` | const | Yes | `"card_network_token"` | +| `token` | string | Yes | Card network token value (DPAN). Omitted from responses. | +| `token_expiry_month` | integer | Yes | Month of the token's expiration date (1-12) | +| `token_expiry_year` | integer | Yes | Year of the token's expiration date | +| `cryptogram` | string | No | One-time-use cryptogram (TAVV/CAVV). Omitted from responses. | +| `eci_value` | string | No | Electronic Commerce Indicator / Security Level Indicator | +| `name` | string | No | Cardholder name. Required by some PSPs (e.g., Adyen). | +| `token_requestor_id` | string | No | Token Requestor ID (TRID) from the card network | + +**Required vs optional fields reflect PSP reality:** + +- `token` and `token_expiry_*` are universally required by all PSPs +- `cryptogram` and `eci_value` are conditional: required for customer-initiated + transactions (CIT) but may be omitted for merchant-initiated transactions + (MIT/recurring) +- `name` is optional because only some PSPs (e.g., Adyen) require it +- `token_requestor_id` is optional; relevant when the token presenter differs + from the provisioner + +**Response omission:** `token` and `cryptogram` use `ucp_response: "omit"` to +prevent sensitive data leakage in API responses, following the pattern from +`token_credential.json`. + +## Instrument Schema + +### `card_network_token_instrument.json` + +Network tokens are cards — they share display properties (brand, last digits, +expiry, card art) with card instruments. The instrument extends +`card_payment_instrument.json`: + +```json +{ + "allOf": [ + { "$ref": "card_payment_instrument.json" }, + { + "type": "object", + "required": ["type"], + "properties": { + "type": { "const": "card_network_token" }, + "credential": { + "$ref": "card_network_token_credential.json" + } + } + } + ] +} +``` + +The instrument inherits the card display properties (`brand`, `last_digits`, +`expiry_month`, `expiry_year`, `card_art`) from the card instrument schema. + +### Available Instrument Variant + +The schema defines `available_card_network_token_instrument` in `$defs`, +extending `available_card_payment_instrument` to inherit `constraints.brands`: + +```json +{ + "$defs": { + "available_card_network_token_instrument": { + "allOf": [ + { "$ref": "card_payment_instrument.json#/$defs/available_card_payment_instrument" }, + { + "type": "object", + "properties": { + "type": { "const": "card_network_token" } + } + } + ] + } + } +} +``` + +## How Network Tokens Fit the Handler Model + +Network tokens are **pre-provisioned credentials** that bypass the +tokenize/detokenize flow: + +1. **Negotiation** — The business's handler declares `available_instruments` + including `card_network_token`. The platform sees that the handler accepts + network token instruments. +2. **Acquisition** — No tokenizer round-trip is needed. The platform constructs + the instrument from a pre-provisioned network token, including a fresh + cryptogram from the card network. +3. **Completion** — The platform submits the `card_network_token` instrument. + The business's PSP processes the network token directly. + +This is analogous to how wallet handlers (e.g., Google Pay, Shop Pay) work: +the platform holds a pre-provisioned opaque credential and presents it +directly. + +## Usage Example + +A platform presenting a pre-provisioned Visa network token at checkout: + +```json +{ + "payment": { + "instruments": [ + { + "id": "pi_ntoken_001", + "handler_id": "handler_merchant_psp", + "type": "card_network_token", + "credential": { + "type": "card_network_token", + "token": "4895370012003478", + "token_expiry_month": 12, + "token_expiry_year": 2028, + "name": "Jane Doe", + "cryptogram": "AJkBBkhAAAAA0YFAAAAAAAAAAA==", + "eci_value": "05", + "token_requestor_id": "40012345678" + }, + "display": { + "brand": "visa", + "last_digits": "3478", + "expiry_month": 12, + "expiry_year": 2028 + }, + "selected": true + } + ] + } +} +``` diff --git a/mkdocs.yml b/mkdocs.yml index 89270a8e5..a5ab6a339 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -62,6 +62,7 @@ nav: - Payment Handlers: - Guide: specification/payment-handler-guide.md - Template: specification/payment-handler-template.md + - Card Network Token: specification/card-network-token.md - Tokenization Guide: specification/tokenization-guide.md - Examples: - Processor Tokenizer: specification/examples/processor-tokenizer-payment-handler.md @@ -236,6 +237,7 @@ plugins: - specification/identity-linking.md - specification/payment-handler-guide.md - specification/payment-handler-template.md + - specification/card-network-token.md - specification/tokenization-guide.md - specification/examples/processor-tokenizer-payment-handler.md - specification/examples/platform-tokenizer-payment-handler.md diff --git a/source/schemas/shopping/types/card_network_token_credential.json b/source/schemas/shopping/types/card_network_token_credential.json new file mode 100644 index 000000000..20477ccd3 --- /dev/null +++ b/source/schemas/shopping/types/card_network_token_credential.json @@ -0,0 +1,47 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://ucp.dev/schemas/shopping/types/card_network_token_credential.json", + "title": "Card Network Token Credential", + "description": "Credential for card network tokens (e.g., Visa VTS, Mastercard MDES). Network tokens are opaque credentials that replace raw PANs, reducing PCI DSS compliance scope.", + "allOf": [ + { "$ref": "payment_credential.json" }, + { + "type": "object", + "required": ["type", "token", "token_expiry_month", "token_expiry_year"], + "properties": { + "type": { "const": "card_network_token" }, + "token": { + "type": "string", + "description": "Card network token value (DPAN).", + "ucp_response": "omit" + }, + "token_expiry_month": { + "type": "integer", + "description": "The month of the token's expiration date (1-12)." + }, + "token_expiry_year": { + "type": "integer", + "description": "The year of the token's expiration date." + }, + "cryptogram": { + "type": "string", + "description": "One-time-use cryptogram (TAVV/CAVV) for authorization.", + "ucp_response": "omit" + }, + "eci_value": { + "type": "string", + "description": "Electronic Commerce Indicator / Security Level Indicator.", + "examples": ["05", "07"] + }, + "name": { + "type": "string", + "description": "Cardholder name. Required by some PSPs (e.g., Adyen)." + }, + "token_requestor_id": { + "type": "string", + "description": "Token Requestor ID (TRID) from the card network." + } + } + } + ] +} diff --git a/source/schemas/shopping/types/card_network_token_instrument.json b/source/schemas/shopping/types/card_network_token_instrument.json new file mode 100644 index 000000000..52bc7451d --- /dev/null +++ b/source/schemas/shopping/types/card_network_token_instrument.json @@ -0,0 +1,37 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://ucp.dev/schemas/shopping/types/card_network_token_instrument.json", + "title": "Card Network Token Payment Instrument", + "description": "A card network token payment instrument. Extends card_payment_instrument with network token credential.", + "$defs": { + "available_card_network_token_instrument": { + "title": "Available Card Network Token Instrument", + "description": "Declares card network token instrument availability with card-specific constraints.", + "allOf": [ + { "$ref": "card_payment_instrument.json#/$defs/available_card_payment_instrument" }, + { + "type": "object", + "properties": { + "type": { "const": "card_network_token" } + } + } + ] + } + }, + "allOf": [ + { "$ref": "card_payment_instrument.json" }, + { + "type": "object", + "required": ["type"], + "properties": { + "type": { + "const": "card_network_token", + "description": "Indicates this is a card network token payment instrument." + }, + "credential": { + "$ref": "card_network_token_credential.json" + } + } + } + ] +}