feat: add card network token credential and instrument types#296
Conversation
Add card_network_token credential and instrument schemas enabling platforms to present pre-provisioned card network tokens (Visa VTS, Mastercard MDES, Amex Token Service) directly at checkout. Separates network tokens from the PCI-scoped card_credential.json, aligning with UCP's stated design intent for opaque credentials.
599e3d7 to
c6e8648
Compare
There was a problem hiding this comment.
👋 Hey @jamesandersen thanks for the PR!
I want to level-set, since I think there's a bit of a disconnect in your summary of the issue vs. some of your deeper discussion points.
However, there is no support for card network tokens
We do already have network tokens represented on the base card credential: https://github.com/Universal-Commerce-Protocol/ucp/blob/main/source/schemas/shopping/types/card_credential.json
We take a similar approach as many processor APIs and agentic commerce specs which have defined this as a unified credential type instead of separating them.
From my POV this intersects nearly 1-1 with your proposed network token credential, with the exception being that the TRID is not on that schema, because TRIDs are not required for processing.
What I do love from this conversation is that it engages with our current documentation and perhaps some incorrect edges around PCI. Do you see an opportunity for us to improve our messaging about how to use the tokenization handler guide, or how to avoid making platforms or businesses think they MUST have PCI compliance to jump into using our current schemas? I would love to steer this PR in that direction instead, which I think I see some hints as buried in your PR comment :)
|
Thanks @raginpirate! I appreciate you taking the time to walk through this. You're right — I initially missed the I'd like to pivot this PR to two concrete changes: 1. Add The one field I think is worth adding to the existing schema. The TRID is assigned by card networks (Visa VTS, Mastercard MDES) to each enrolled token requestor — it identifies who provisioned a given network token. This matters in platform commerce scenarios where the entity presenting the token at checkout differs from the entity that originally provisioned it (e.g., a platform holds tokens under its own TRID but submits them through a merchant's PSP). Braintree includes it as an optional field in their 2. Documentation improvements for network token usage and PCI scope The tokenization guide does a great job covering the FPAN → token flow, but doesn't address the pre-provisioned network token path — where a platform already holds a network token and presents it directly at checkout without a tokenize/detokenize round-trip. I'd propose adding:
Happy to rework this PR or start fresh — which do you prefer? |
|
Hey @jamesandersen! A few questions on #1 above.
|
|
@kmcduffie As I understand it, in the most common flow — where the handler's PSP provisioned the token — the PSP already knows the TRID and attaches it to the authorization automatically. I'd guess that why most PSP APIs treat it as optional; the merchant never needs to provide it. Where I think it becomes relevant is "Bring Your Own Token" (BYOT) scenarios — where the entity that provisioned the token differs from the entity presenting it for authorization. IIUC this would be the primary use case of For that reason I think the TRID fits best on the credential rather than merchant config because in the BYOT case, the merchant may not know or own the TRID — it belongs to whoever provisioned the token i.e. the platform in UCP framing. |
|
@jamesandersen Thanks for the reference to the Braintree APIs. I see that the field is optional. Do you know how that field is used by PSPs? |
|
@kmcduffie I've been digging a bit to better understand myself; this gets a little beyond my day to day context... My understanding is that the TRID is needed in the authorization message itself — not just at cryptogram generation time — for cryptogram validation. Since the cryptogram output is a binary blob that doesn't identify which token requestor generated it, at authorization time, the network needs the TRID as a separate field to look up the correct cryptographic keys and validate the cryptogram, check transaction counters, etc. against the right token requestor's provisioning record. I think downstream at the issuer they may have trust profiles for different TRIDs but by that time the network would be able to provide the TRID. In the UCP context I'm still primarily imagining use of |
I you have a business case that requires it, I don't see a reason to block this optional field from the spec. But as @kmcduffie is poking at, I wasn't able to confirm a normal reason that processors (or businesses in front of them) are trying to handle that value ahead of it reaching the network. For example, agentic network tokens leaning on the cvv to proxy the cryptogram, would certainly not leverage TRID as an external data point.
Yeah I would love to see your iteration on this 😄 I think your proposals make sense and I am very happy to see more clear documentation about when / why PCI intersects with UCP 🚀 Probably nice to close this PR and open one with a more targeted title and referencing this to preserve history, but thats up to you! |
|
@raginpirate good comments above. For #1 - we may be straying into the theoretical on whether TRID is needed for a BYOT scenario (only have Braintree docs as a more concrete support). I may have some more tangible experience to bring to this in a few months. For now, I'm content just dropping the TRID property I'll follow your suggestion and open a hopefully more straightforward PR for a couple docs clarifications ... but a bit later (it's late!) |
Add documentation for pre-provisioned network token usage and PCI scope distinctions between FPAN and network token credential modes: - Add "Pre-Provisioned Network Tokens" section to the tokenization guide covering the BYOT path where platforms present card network tokens directly as card_number_type: "network_token" without a tokenize/detokenize round-trip - Add network token bullet to Platform PCI Scope in the overview - Update card_credential.json description to distinguish PCI scope between fpan (full PCI DSS) and network_token (reduced scope) References Universal-Commerce-Protocol#296 — split from the original card network token credential PR into a focused docs-only change per reviewer feedback.
Enhancement Proposal: Card Network Token Credential Type
Summary
A new
card_network_tokencredential type for UCP that enables platforms to present card network tokens (Visa VTS, Mastercard MDES, Amex Token Service) directly as payment credentials in checkout sessions — without requiring re-tokenization through a handler or falling back to raw PANs.Motivation
UCP currently supports payment tokenization through handler-specific tokens and a delegated payment model. However, there is no support for card network tokens — tokenized card credentials issued by card networks that replace the primary account number (PAN) with a network-level token.
Card network tokens are an industry-standard payment security mechanism with broad PSP acceptance. Every major processor supports directly processing network tokens with the same core fields (token/DPAN, cryptogram, ECI):
UCP's own specification explicitly identifies network tokens as a mechanism for platforms to avoid PCI-DSS scope:
Yet despite this design intent, UCP currently has no dedicated credential type for network tokens. Platforms that already hold card network tokens cannot use them directly.
Token Provisioning
Platforms can obtain card network tokens through several standard provisioning channels:
Goals
allOfwith base schemas)ucp_response: "omit"Non-Goals
card_credential.jsonschemaRelated Work
card_credential.jsonincludes partial network token support viacard_number_type: "network_token"withcryptogramandeci_valuefields. See "Discussion Points" below for why a separate credential type is proposed.card_payment_instrument.json— defines the card instrument with display properties and theavailable_card_payment_instrumentvariant withconstraints.brands.token_credential.json— base token credential withucp_response: "omit"pattern ontokenfield.available_instrumentswith constraints.Detailed Design
Credential Schema: card_network_token_credential.json
The credential extends
payment_credential.jsonviaallOf:type"card_network_token"tokentoken_expiry_monthtoken_expiry_yearcryptogrameci_valuenametoken_requestor_idInstrument 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.jsonand includes anavailable_*variant following the established pattern:brand,last_digits,expiry_month,expiry_year,card_art)available_card_network_token_instrumentextendingavailable_card_payment_instrumentto inheritconstraints.brandscard_network_token_credential.jsonvia thecredentialpropertyHow Network Tokens Fit the Handler Model
Network tokens are pre-provisioned credentials that bypass the tokenize/detokenize flow:
available_instrumentsincludingcard_network_token.card_network_tokeninstrument. 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.
Relationship to Existing card_credential.json
The current
card_credential.jsonincludes partial network token support viacard_number_type: "network_token". However, that schema carries PCI restrictions that apply to the entire schema:A separate credential type is proposed because:
card_credential.jsonlackstoken_requestor_idand has no way to distinguish token expiry from card expiry (network tokens have independent expiry dates).card_credentialimplies the platform holds PCI-scoped card data when it does not.Alternative approach: The community could choose to enhance
card_credential.jsonwith the missing fields and relax the PCI restriction whencard_number_typeis"network_token". Either approach achieves the same functional goal. This is an explicit discussion point.Usage Example
A platform presenting a pre-provisioned Visa network token at checkout:
{ "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 } ] } }Design Rationale
payment_credential.jsonviaallOf; instrument extendscard_payment_instrument.jsonto inherit display properties andavailable_*variant pattern.card_payment_instrument.json. Cryptogram and eci_value are optional because they are conditional (CIT vs MIT). Name is optional (only Adyen requires it).ucp_response: omit— prevents leaking sensitive data in API responses, following the pattern fromtoken_credential.json.Risks and Mitigations
card_credential.jsonnetwork token supportcard_credential.jsonand presents this as a discussion point for the TC.ucp_response: "omit"ontokenandcryptogramfields prevents leakage.Test Plan
allOfwithpayment_credential.jsonproduces valid combined schematokenor expiry fields are missingtokenandcryptogramare omitted from API responsesGraduation Criteria
Code Changes
New Files:
source/schemas/shopping/types/card_network_token_credential.json— credential schemasource/schemas/shopping/types/card_network_token_instrument.json— instrument schema withavailable_card_network_token_instrumentvariantdocs/specification/card-network-token.md— documentationModified Files:
mkdocs.yml— Added card network token to nav and llmstxt sections.cspell/custom-words.txt— Added network token-related termsNote: No modifications to existing schemas required. Base
payment_credential.jsonusesadditionalProperties: true;card_payment_instrument.jsonis extended viaallOf, not modified.Discussion Points
card_credential.jsonwith conditional PCI relaxation?available_card_network_token_instrumentextendavailable_card_payment_instrument(inheritingconstraints.brands) or define its own constraints?References
payment_credential.json— base credential schemacard_credential.json— existing card credential with partial network token supportcard_payment_instrument.json— card instrument with display properties andavailable_card_payment_instrumentvariantType of change
Checklist