From 6afe86c43a3c89f037041effa9ce5dc491694df8 Mon Sep 17 00:00:00 2001 From: Prasad Wangikar Date: Tue, 1 Sep 2026 08:21:49 -0700 Subject: [PATCH] docs: clarify participant identifier in payment handler examples The three payment handler examples describe the participant identifier three different ways, and one of them teaches the wrong threat model. This aligns the examples with tokenization.md. 1. processor-tokenizer: "Merchant Secure Identifier" framed identity.access_token as a secret, contradicting tokenization.md Binding rule 4, which states that identity is a participant identifier, not a credential, and that a Tokenizer MUST NOT accept it as authentication. Replaced with participant identifier framing, plus a Security Considerations row stating the rule explicitly. 2. processor-tokenizer: a MUST required the credential provider to send the handler configuration's identity object, but no config table or example declaration in that document defines an identity member; the config publishes business_id. Reworded against the config field that exists, using the document's own PSP Mode and Direct Mode framing. 3. platform-tokenizer: the same value appeared as identity.access_token in Prerequisites and as business_id in the config table, with no stated mapping, while three normative statements referenced "the business's identity from the handler declaration". The mapping from config.business_id to identity.access_token is now stated once where the config is defined, and the three statements reference it. config remains handler-defined, per ucp.json#/$defs/entity. 4. encrypted-credential: Prerequisites listed identity.access_token and References pointed at payment_identity.json, but this handler implements neither /tokenize nor /detokenize, and its encrypted payload carries only credential and binding. Replaced with business_id, which the document's own next paragraph already uses, and with binding.json. No schema file is touched. The added Security Considerations row restates tokenization.md Binding rule 4, and item 2 repoints an existing MUST at the config member the examples actually publish. --- .../encrypted-credential-payment-handler.md | 10 +++---- .../platform-tokenizer-payment-handler.md | 28 +++++++++++-------- .../processor-tokenizer-payment-handler.md | 23 +++++++++------ 3 files changed, 35 insertions(+), 26 deletions(-) diff --git a/docs/specification/payment/examples/encrypted-credential-payment-handler.md b/docs/specification/payment/examples/encrypted-credential-payment-handler.md index abef5050c..260b5982b 100644 --- a/docs/specification/payment/examples/encrypted-credential-payment-handler.md +++ b/docs/specification/payment/examples/encrypted-credential-payment-handler.md @@ -110,10 +110,10 @@ compliant** because they will handle raw PANs. This includes: **Prerequisites Output:** -| Field | Description | -| :---------------------- | :--------------------------------------------------------- | -| `identity.access_token` | Business identifier assigned by platform during onboarding | -| Public key registered | Platform stores business's public key for encryption | +| Field | Description | +| :-------------------- | :-------------------------------------------------------------------------------------------- | +| `business_id` | Business identifier assigned by platform during onboarding, published in the handler `config` | +| Public key registered | Platform stores business's public key for encryption | ### Handler Configuration @@ -359,5 +359,5 @@ Content-Type: application/json ## References -* **Identity Schema:** [schemas/common/types/payment_identity.json](site:schemas/common/types/payment_identity.json) +* **Binding Schema:** [schemas/common/types/binding.json](site:schemas/common/types/binding.json) * **Instrument Schema:** [schemas/common/types/card_payment_instrument.json](site:schemas/common/types/card_payment_instrument.json) diff --git a/docs/specification/payment/examples/platform-tokenizer-payment-handler.md b/docs/specification/payment/examples/platform-tokenizer-payment-handler.md index 254f4a50e..293079d9f 100644 --- a/docs/specification/payment/examples/platform-tokenizer-payment-handler.md +++ b/docs/specification/payment/examples/platform-tokenizer-payment-handler.md @@ -163,18 +163,21 @@ Optionally, businesses may configure their PSP to detokenize on their behalf **Prerequisites Output:** -| Field | Description | -| :------------------------- | :------------------------------------------------------------ | -| `identity.access_token` | Business identifier assigned by platform during onboarding | -| Authentication credentials | API key or OAuth token for authenticating `/detokenize` calls | +| Field | Description | +| :------------------------- | :-------------------------------------------------------------------------------------------- | +| `business_id` | Business identifier assigned by platform during onboarding, published in the handler `config` | +| Authentication credentials | API key or OAuth token for authenticating `/detokenize` calls | ### Handler Configuration -Businesses advertise the platform's tokenization handler. The `config` -contains the business's identity with the platform for token binding. The -platform's handler specification (referenced via `spec`) documents the -`/detokenize` endpoint URL exposed by the platform's -**payment credential provider**. +Businesses advertise the platform's tokenization handler. The `config` publishes +the business's identifier with the platform as `business_id`. That value is the +participant identifier the platform issues tokens to, and a caller acting on the +business's behalf sends it as `identity.access_token` on `/detokenize`. A +handler's `config` structure is handler-defined, so another handler **MAY** +publish this identifier under a different member name. The platform's handler +specification (referenced via `spec`) documents the `/detokenize` endpoint URL +exposed by the platform's **payment credential provider**. The handler accepts [PanCredential](site:schemas/common/types/pan_credential.json) and [NetworkTokenCredential](site:schemas/common/types/network_token_credential.json) for tokenization and produces [TokenCredential](site:schemas/common/types/token_credential.json) for checkout. @@ -366,7 +369,7 @@ The platform application orchestrates the payment flow but 1. The platform's **payment credential provider** securely stores payment credentials. 2. When a payment is needed, the platform application requests a token from the credential provider. -3. The credential provider generates a token bound to the `binding` resource and issued to the business's `identity` (from the handler declaration). +3. The credential provider generates a token bound to the `binding` resource and issued to the business's participant identifier (`config.business_id` from the handler declaration). 4. The credential provider returns the token to the platform application. 5. The platform application includes this token in the checkout submission. @@ -461,7 +464,8 @@ When the business forwards a token to the PSP: 1. Extract the token from the payment instrument. 2. Call the platform's **payment credential provider** `/detokenize` endpoint - with the business's `identity` alongside the `binding`. + with the business's participant identifier as `identity.access_token` + alongside the `binding`. 3. Process the payment with the returned credential. #### Detokenize Request Example (PSP) @@ -506,7 +510,7 @@ The platform's payment credential provider verifies that: | **No Platform App access** | Platform applications **MUST NOT** handle sensitive data—only the compliant payment credential provider does. | | **Endpoint isolation** | `/detokenize` endpoint **MUST** be exposed by the payment credential provider, not the platform application. | | **Participant authentication** | Platform's credential provider **MUST** authenticate businesses/PSPs before accepting `/detokenize` calls. | -| **Issued to participant** | Tokens **MUST** be issued to the business's `identity` from the handler declaration. | +| **Issued to participant** | Tokens **MUST** be issued to the business's participant identifier (`config.business_id`) from the handler declaration. | | **Resource-bound** | Tokens **MUST** be bound to the specific `binding` resource. | | **Caller verification** | Platform **MUST** verify the authenticated caller is the participant the token was issued to (or is an authorized PSP). | | **Single-use** | Tokens **SHOULD** be invalidated after detokenization. | diff --git a/docs/specification/payment/examples/processor-tokenizer-payment-handler.md b/docs/specification/payment/examples/processor-tokenizer-payment-handler.md index 008508c39..3c6cccb6f 100644 --- a/docs/specification/payment/examples/processor-tokenizer-payment-handler.md +++ b/docs/specification/payment/examples/processor-tokenizer-payment-handler.md @@ -100,10 +100,10 @@ The business advertises their tokenization endpoint and identity during discover The handler's specification (referenced via the `spec` field) documents the `/tokenize` endpoint URL. -| Field | Type | Required | Description | -| :------------ | :----- | :------- | :------------------------------------------ | -| `environment` | string | Yes | API environment (`sandbox` or `production`) | -| `business_id` | string | Yes | Business identifier with the processor | +| Field | Type | Required | Description | +| :------------ | :----- | :------- | :------------------------------------------------------------------------------------------------- | +| `environment` | string | Yes | API environment (`sandbox` or `production`) | +| `business_id` | string | Yes | Business identifier with the processor. Sent as `identity.access_token` on `/tokenize` in PSP Mode | #### Example Business Handler Declaration @@ -228,8 +228,10 @@ that ensures the sensitive instrument details never touch the platform). Platform's payment credential provider calls the configured `endpoint`. -**Note:** If the handler configuration includes an `identity` object, the -credential provider **MUST** include it in the request alongside `binding`. +**Note:** In PSP Mode the credential provider **MUST** send the business's +participant identifier as `identity.access_token` alongside `binding`, using the +value the business publishes in `config.business_id`. In Direct Mode the +business is the authenticated caller and `identity` is omitted. Response: @@ -297,9 +299,11 @@ Content-Type: application/json * **Role:** The PSP implements this specification. * **Requirements:** 1. Provide the `endpoint` URL to merchants. - 2. Issue `identity.access_token` (Merchant Secure Identifier) to merchants. - 3. Validate that the `identity` matches the merchant requesting - the final payment charge. + 2. Assign each merchant a participant identifier at onboarding. The merchant + publishes it as `config.business_id`, and the platform's credential provider + sends it as `identity.access_token` on `/tokenize`. + 3. Validate that the participant identifier the token was issued to matches + the merchant requesting the final payment charge. * **Security:** PSP bears the compliance burden for credential storage (e.g., PCI DSS for cards). @@ -313,3 +317,4 @@ Content-Type: application/json | **Compliance** | The entity hosting `config.endpoint` **MUST** be compliant with relevant data standards for the credential type (e.g., PCI DSS for cards, GDPR for PII, etc.). | | **Scope Isolation** | The Platform's main application **MUST NOT** see the raw credential; only the Platform's Secure credential provider and the Tokenizer Host may see it. | | **Binding Validation** | The Tokenizer/Processor **MUST** verify that the `binding` submitted during final payment matches the `binding` provided during tokenization. | +| **Participant Identity** | `identity.access_token` is a participant identifier, not a credential. The Tokenizer/Processor authenticates the caller separately and **MUST NOT** accept `identity` as authentication. See [Binding](../tokenization.md#binding). |