Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .cspell/custom-words.txt
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,7 @@ amortiguación
atok
backorder
barcodes
cartebancaire
checkout
cimd
credentialization
Expand Down
2 changes: 1 addition & 1 deletion docs/documentation/schema-authoring.md
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ Define payment handler configurations in `ucp.payment_handlers{}` registries.
- **Top-level fields**: `$schema`, `$id`, `title`, `description`, `name`, `version`, `available_instruments`
- **Variants**: `platform_schema`, `business_schema`, `response_schema`
- **Instance `id`**: Required to distinguish multiple configurations of the same handler
- **`available_instruments`**: Optional. Array of supported instrument types with type-specific constraints (e.g., brands for credit cards). When absent, the handler places no restrictions — it supports the full set of instrument types defined by its handler schema.
- **`available_instruments`**: Optional. Array of supported instrument types, each with an optional Constraint Expression over type-specific members (e.g., `brand` for credit cards). When absent, the handler places no restrictions — it supports the full set of instrument types defined by its handler schema.

Examples: `com.google.pay`, `dev.shopify.shop_pay`, `dev.ucp.processor_tokenizer`

Expand Down
54 changes: 37 additions & 17 deletions docs/specification/overview/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,14 @@ that member is present, so a branch pinning a discriminator through
discriminator in the branch's `required` makes the branch match only the shape
it describes.

The grammar is defined independently of the object it is bound to. Request
Constraints bind it to objects in the next request and add `path`; other UCP
schemas reuse it where a declaration already identifies the object it
constrains, such as
[`available_instruments[].constraints`](site:schemas/shopping/types/available_payment_instrument.json),
whose object is the `constraint_target` declared by the instrument schema for
that entry's `type`.

### Path

Every `request_constraints` value has exactly one effective path. When `path`
Expand Down Expand Up @@ -550,8 +558,10 @@ payment policy.
#### Alternative verification requirements on a submitted credential

A Business accepts more than one credential shape and requires different
verification data for each. In this example, a raw PAN must carry a `cvc`, and a
network token must carry a `cryptogram` with its `eci_value`:
verification data for each. In this example, a PAN must carry a `cvc`, and a
network token must carry a `cryptogram` with its `eci_value`. Each credential
family is its own schema, so every branch discriminates on the credential's own
`type` and no rule has to branch on a sibling field:

<!-- ucp:example schema=shopping/types/available_payment_instrument op=read direction=response -->
```json
Expand All @@ -565,12 +575,12 @@ network token must carry a `cryptogram` with its `eci_value`:
"credential": {
"anyOf": [
{
"properties": {"card_number_type": {"const": "fpan"}},
"required": ["card_number_type", "cvc"]
"properties": {"type": {"const": "pan"}},
"required": ["cvc"]
},
{
"properties": {"card_number_type": {"const": "network_token"}},
"required": ["card_number_type", "cryptogram", "eci_value"]
"properties": {"type": {"const": "network_token"}},
"required": ["cryptogram", "eci_value"]
}
]
}
Expand All @@ -583,20 +593,26 @@ network token must carry a `cryptogram` with its `eci_value`:
One path selects the submitted instrument, and one Object Constraint describes
it. The sibling `required` applies to every matching instrument; the `anyOf`
branches then apply to the nested `credential` object, which must satisfy at
least one. Each branch pins `card_number_type` and also names it in `required`,
so a branch matches only the credential shape it describes. A raw PAN without a
`cvc` fails, as does a network token missing its `eci_value`.
least one. Each branch pins `type` with `const`, so a branch matches only the
credential family it describes;
[`payment_credential.json`](site:schemas/shopping/types/payment_credential.json)
already requires `type` on every credential, so no branch has to name it in
`required`. A [PAN credential](site:schemas/shopping/types/pan_credential.json)
without a `cvc` fails, as does a [network
token](site:schemas/shopping/types/network_token_credential.json) missing its
`eci_value`.

Because every branch pins the discriminator, the branch set also closes the
accepted values. A `dpan` credential is valid under
[`card_credential.json`](site:schemas/shopping/types/card_credential.json) but
satisfies neither branch, so this Business does not accept it at this path. A
Business that later accepts a new variant adds a branch for it.
accepted credential families. A handler
[token credential](site:schemas/shopping/types/token_credential.json) is a valid
credential at this position but satisfies neither branch, so this Business does
not accept it at this path. A Business that later accepts another family adds a
branch for it.

Two separately targeted constraints cannot express this rule. Request
Constraints conjoin, so one value requiring `cvc` and another requiring
`cryptogram` would require both. Discriminating through the path filter instead
— selecting `fpan` credentials in one value and `network_token` credentials in
— selecting `pan` credentials in one value and `network_token` credentials in
another — moves conditional logic into the selector, which paths do not carry.

## Actions
Expand Down Expand Up @@ -1356,7 +1372,7 @@ Businesses publish their profile at `/.well-known/ucp`. An example:
{
"type": "card",
"constraints": {
"brands": ["visa", "mastercard", "amex"]
"properties": { "brand": { "enum": ["visa", "mastercard", "amex"] } }
}
}
],
Expand Down Expand Up @@ -1517,7 +1533,7 @@ example:
"spec": "https://example.com/specs/payments/processor_tokenizer-payment",
"schema": "https://example.com/schemas/payments/delegate-payment.json",
"available_instruments": [
{"type": "card", "constraints": {"brands": ["visa", "mastercard"]}}
{"type": "card", "constraints": {"properties": {"brand": {"enum": ["visa", "mastercard"]}}}}
]
}
]
Expand Down Expand Up @@ -2709,7 +2725,7 @@ request a challenge.
{
"type": "card",
"constraints": {
"brands": ["visa", "mastercard"]
"properties": { "brand": { "enum": ["visa", "mastercard"] } }
}
}
],
Expand Down Expand Up @@ -2854,6 +2870,10 @@ Most platform implementations can **avoid PCI-DSS scope** by:
- Forwarding credentials without the ability to use them directly
- Using PSP tokenization payment handlers where raw credentials never pass
through the platform
- Presenting pre-provisioned card network tokens
(`network_token_credential.json`) rather than an FPAN — the platform never
shares the underlying account number, and the token is unusable without a
matching cryptogram

#### Business Scope

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -121,11 +121,11 @@ Businesses advertise the platform's handler. The `business_id` field identifies
the business, which the platform uses to look up the correct public key for
encryption.

The only supported instrument schema is [CardPaymentInstrument](site:schemas/shopping/types/card_payment_instrument.json), the only supported checkout credential schema is `EncryptedCredential`, and the only supported source credential schema is [CardCredential](site:schemas/shopping/types/card_credential.json).
The only supported instrument schema is [CardPaymentInstrument](site:schemas/shopping/types/card_payment_instrument.json), the only supported checkout credential schema is `EncryptedCredential`, and the only supported source credential schema is [PanCredential](site:schemas/shopping/types/pan_credential.json).

**Note:** The `EncryptedCredential` shape would be formally defined in the handler's schema (referenced via the `schema` field in the handler declaration).

**Note:** `CardCredential` contains raw PANs. For card credentials, the
**Note:** `PanCredential` contains raw PANs. For card credentials, the
platform's vaulting service must be **PCI DSS compliant** when handling these
credentials. Businesses receive only encrypted payloads but must be PCI DSS
compliant once they decrypt card credentials locally. Other credential types
Expand Down Expand Up @@ -157,7 +157,7 @@ have their own compliance requirements.
{
"type": "card",
"constraints": {
"brands": ["visa", "mastercard"]
"properties": { "brand": { "enum": ["visa", "mastercard"] } }
}
}
],
Expand Down Expand Up @@ -195,7 +195,7 @@ The response config includes information about the encryption used.
{
"type": "card",
"constraints": {
"brands": ["visa", "mastercard"]
"properties": { "brand": { "enum": ["visa", "mastercard"] } }
}
}
],
Expand Down Expand Up @@ -269,7 +269,7 @@ registry using `platform_config`.
{
"type": "card",
"constraints": {
"brands": ["visa", "mastercard", "amex", "discover"]
"properties": { "brand": { "enum": ["visa", "mastercard", "amex", "discover"] } }
}
}
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ platform's handler specification (referenced via `spec`) documents the
`/detokenize` endpoint URL exposed by the platform's
**payment credential provider**.

The handler accepts [CardCredential](site:schemas/shopping/types/card_credential.json) for tokenization and produces [TokenCredential](site:schemas/shopping/types/token_credential.json) for checkout.
The handler accepts [PanCredential](site:schemas/shopping/types/pan_credential.json) and [NetworkTokenCredential](site:schemas/shopping/types/network_token_credential.json) for tokenization and produces [TokenCredential](site:schemas/shopping/types/token_credential.json) for checkout.

**Note:** The result of `/detokenize` contains **sensitive payment data**.
Both the sender (platform's credential provider) and receiver
Expand Down Expand Up @@ -208,7 +208,7 @@ credential type (e.g., PCI DSS for cards).
{
"type": "card",
"constraints": {
"brands": ["visa", "mastercard"]
"properties": { "brand": { "enum": ["visa", "mastercard"] } }
}
}
],
Expand Down Expand Up @@ -244,7 +244,7 @@ The response config includes runtime token lifecycle information.
{
"type": "card",
"constraints": {
"brands": ["visa", "mastercard"]
"properties": { "brand": { "enum": ["visa", "mastercard"] } }
}
}
],
Expand Down Expand Up @@ -342,7 +342,7 @@ registry using `platform_config`.
{
"type": "card",
"constraints": {
"brands": ["visa", "mastercard", "amex", "discover"]
"properties": { "brand": { "enum": ["visa", "mastercard", "amex", "discover"] } }
}
}
],
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ The handler's specification (referenced via the `spec` field) documents the
{
"type": "card",
"constraints": {
"brands": ["visa", "mastercard", "amex"]
"properties": { "brand": { "enum": ["visa", "mastercard", "amex"] } }
}
}
],
Expand Down Expand Up @@ -158,7 +158,7 @@ The response config includes runtime information about what's available for this
{
"type": "card",
"constraints": {
"brands": ["visa", "mastercard", "amex"]
"properties": { "brand": { "enum": ["visa", "mastercard", "amex"] } }
}
}
],
Expand Down Expand Up @@ -205,7 +205,7 @@ business's configuration.
"id": "processor_tokenizer",
"version": "{{ ucp_version }}",
"available_instruments": [
{"type": "card", "constraints": {"brands": ["visa", "mastercard", "amex"]}}
{"type": "card", "constraints": {"properties": {"brand": {"enum": ["visa", "mastercard", "amex"]}}}}
],
"config": {
"environment": "production",
Expand Down
Loading
Loading