Payment Handler Specification Guide¶
Introduction¶
This guide defines the standard structure and vocabulary for specifying UCP payment handlers. All payment handler specifications SHOULD follow this structure to ensure consistency, completeness, and clarity for implementers.
Purpose¶
Payment handlers enable "N-to-N" interoperability between platforms, businesses, and payment providers. A well-specified handler must answer these questions for each participant:
- Who participates? What participants are involved and what are their roles?
- What are the prerequisites? What onboarding or setup is required?
- How is it configured? What configuration is advertised or consumed?
- How is it executed? What protocol is followed to acquire or process instruments?
This guide provides a framework that ensures every handler specification answers these questions systematically.
Scope¶
This guide applies to:
- Handlers (e.g.,
com.google.pay,dev.shopify.shop_pay) — Specific payment method implementations
Core Concepts¶
Every payment handler specification MUST define the core elements below.
Note on Protocol Signatures:: The function signatures provided in this
section (e.g., PROCESSING(...)) represent logical data flows, not literal
function calls. Spec authors must map these logical flows to the actual
transport protocol used by their implementation.
+------------------------------------------------------------------------------+
| Payment Handler Framework |
+------------------------------------------------------------------------------+
| |
| +--------------+ |
| | PARTICIPANTS | Who participates in this handler? |
| +------+-------+ |
| | |
| v |
| +--------------+ |
| |PREREQUISITES | How does each participant obtain identity & configs? |
| +------+-------+ |
| | |
| +--------------------+----------------------+ |
| v v v |
| +--------------+ +--------------+ +--------------+ |
| | HANDLER | | INSTRUMENT | | PROCESSING | |
| | DECLARATION | | ACQUISITION | | | |
| +--------------+ +--------------+ +--------------+ |
| Business advertises platform acquires Participant |
| handler config checkout instrument processes instrument |
| |
+------------------------------------------------------------------------------+
Participants¶
Definition: The distinct actors that participate in the payment handler's lifecycle. Every handler has at minimum two participants (business and platform), but MAY define additional participants with specific roles.
Note on Terminology:: While this guide refers to the participant as the
"Business", technical schema fields may retain the standard industry
nomenclature merchant_* (e.g., merchant_id, merchant_name).
Specifications MUST explicitly document these field mappings.
Standard Participants:
| Participant | Role |
|---|---|
| Business | Advertises handler configuration, processes payment instruments |
| Platform | Discovers handlers, acquires payment instruments, submits checkout |
Extended Participants (example handler-specific participants):
| Participant | Example Role |
|---|---|
| Tokenizer | Stores raw credentials and issues token credentials |
| PSP | Processes payments on behalf of business using the checkout instrument |
Prerequisites¶
Definition: The onboarding, setup, or configuration a participant must complete before participating in the handler's flows.
Signature:
| Field | Description |
|---|---|
participant |
The participant being onboarded (business, platform, etc.) |
onboarding_input |
What the participant provides during setup |
prerequisites_output |
The identity and any additional configuration received |
Prerequisites Output:
The prerequisites_output contains what a participant receives from onboarding.
At minimum, this includes an identity (see Payment Identity).
It MAY also include additional configuration, credentials, or settings
specific to the handler.
Payment handler specifications are not required to define a formal schema
for prerequisites_output. Instead, the specification SHOULD clearly
document:
- What identity is assigned (and how it maps to
PaymentIdentity) - What additional configuration is provided
- How the prerequisites output is used in Handler Declaration, Instrument Acquisition, or Processing
Notes:
- Prerequisites typically occur out-of-band (portals, contracts, API calls)
- Multiple participants MAY have independent prerequisites
- The identity from prerequisites typically appears within the handler's
configobject (e.g., asmerchant_idor similar handler-specific field) - Participants receiving raw credentials (e.g., businesses, PSPs) typically must complete security acknowledgements during onboarding, accepting responsibility for credential handling and compliance
Handler Declaration¶
Definition: The configuration a business advertises to indicate support for this handler and enable platforms to invoke it.
Signature:
| Field | Description |
|---|---|
prerequisites_output |
The identity and configuration from business prerequisites |
handler_declaration |
The handler object advertised in ucp.payment_handlers |
Output Structure:
The handler declaration conforms to the PaymentHandler
schema. The specification SHOULD define the available config and instrument
schemas, and how to construct each based on the business's prerequisites output
and desired configuration.
{
"com.example.handler": [
{
"id": "processor_tokenizer_1234",
"version": "draft",
"spec": "https://example.com/ucp/handler",
"schema": "https://example.com/ucp/handler/schema.json",
"available_instruments": [ ... ],
"config": {
// Handler-specific configuration (see Config Shapes)
}
}
]
}
available_instruments is optional. When absent, the handler places no
restrictions on instrument types or constraints — it supports the full set of
instrument types defined by its handler schema. When present, it narrows the
advertised types and/or applies additional constraints (e.g., limiting card
brands to visa and mastercard). In a Business profile and authoritative
response, array order communicates preferred instrument presentation, earliest
first.
Each entry narrows along two axes. Both are Constraint Expressions, so one evaluator runs both; they differ only in the object they describe:
available_instruments[]
├── type selects an instrument schema
├── constraints describes that schema's `constraint_target`
└── ucp.request_constraints describes the request that submits it, via `path`
constraints admits no path. Its object is standing, not selected: the
instrument schema for the entry's type declares it as $defs/constraint_target,
and keys in properties name that object's members. The target holds what the
Business derives rather than receives — for cards, brand, read from the account
number and surviving tokenization — which is why those values cannot be expressed
as requirements on request data.
ucp.request_constraints carries everything that is on the wire: which
instrument fields are required, which credential types are accepted, and which
fields each of those credential types must carry. Use field requirements rather
than handler-specific booleans for modeled data.
When an authoritative response includes ucp.request_constraints on an
available instrument, the Business MUST include an explicit path because
the available instrument's response Normalized Path does not identify submitted
instruments. The path matches the containing handler's id
to submitted handler_id and the available instrument's type to submitted
type, and applies when the next request contains matching instruments.
Payment-handler and instrument specifications define any stronger association
the query needs. See Request Constraints.
One path selects the submitted instrument, and one Constraint Expression
describes it. Requirements shared by every instrument of the type are sibling
members; requirements that differ per credential family are anyOf branches on
the nested credential object. Splitting the credential families into distinct
schemas is what gives each branch a stable discriminator.
{
"id": "processor_tokenizer_1234",
"version": "draft",
"available_instruments": [
{
"type": "card",
"constraints": { "properties": { "brand": { "enum": ["visa", "mastercard"] } } },
"ucp": {
"request_constraints": {
"path": "$['payment']['instruments'][?@['handler_id'] == 'processor_tokenizer_1234' && @['type'] == 'card']",
"required": ["billing_address", "credential"],
"properties": {
"billing_address": { "required": ["postal_code", "address_country"] },
"credential": {
"anyOf": [
{ "properties": { "type": { "const": "pan" } }, "required": ["cvc"] },
{ "properties": { "type": { "const": "network_token" } } }
]
}
}
}
}
}
]
}
The sibling members apply to every card instrument from this handler. The
branches accept either a PAN credential carrying a cvc or a network token,
which network_token_credential.json already requires to carry a cryptogram;
a credential of any other type satisfies neither branch. Declared constraints
are the upfront minimum; dynamic requirements still use recoverable errors and
message_error.path.
Handler Declaration Variants¶
The PaymentHandler schema defines three variants for different contexts. While only
id and version are technically required, each variant serves a distinct purpose
and typically includes different configuration:
| Variant | Context | Purpose |
|---|---|---|
| business_schema | Business discovery (/.well-known/ucp) |
Declares the business identity and how they're configured for this handler. Contains merchant-specific settings. |
| platform_schema | Platform profile (advertised URI) | Declares the platform identity and how it supports this handler. Includes spec and schema URLs for implementers. |
| response_schema | Checkout/Order API responses | Runtime configuration with resolved context: merchant identity, resolved available_instruments for this checkout, tokenization specs, and other state needed to process the transaction. Platforms MUST treat this as authoritative. |
Business Schema Example (business declares handler configuration):
{
"id": "processor_tokenizer_1234",
"version": "draft",
"spec": "https://example.com/ucp/handler",
"schema": "https://example.com/ucp/handler/schema.json",
"available_instruments": [
{
"type": "card",
"constraints": {
"properties": { "brand": { "enum": ["visa", "mastercard"] } }
}
}
],
"config": {
"environment": "production",
"business_id": "business_xyz_789"
}
}
Platform Schema Example (platform declares handler support):
{
"id": "platform_tokenizer_2345", // note: ids are for disambiguation, they may differ between business and platform
"version": "draft",
"spec": "https://example.com/ucp/handler",
"schema": "https://example.com/ucp/handler/schema.json",
"available_instruments": [
{
"type": "card",
"constraints": {
"properties": { "brand": { "enum": ["visa", "mastercard", "amex", "discover"] } }
}
}
],
"config": {
"environment": "production",
"platform_id": "platform_abc_123"
}
}
Response Schema Example (runtime context for checkout):
{
"id": "processor_tokenizer_1234",
"version": "draft",
"available_instruments": [
{
"type": "card",
"constraints": {
"properties": { "brand": { "enum": ["visa", "mastercard"] } }
}
}
],
"config": {
"api_version": 2,
"environment": "production",
"business_id": "business_xyz_789"
}
}
Resolving available_instruments¶
Both the platform and the business independently advertise available_instruments
in their profiles. The business is responsible for resolving these into the
authoritative value returned in the response_schema.
Resolution flow:
-
Platform declares capabilities — the platform's profile includes
available_instrumentson each handler declaration. This tells the business what the platform can handle (e.g., it only supports["visa", "mastercard", "amex", "discover"]). -
Business resolves — upon receiving a request, the business computes the resolved
available_instrumentsfor the checkout by intersecting: - The platform's advertised
available_instruments(its capabilities) - Its own
business_schemadeclaration (what the merchant is actually set up to accept) -
Cart/checkout context (e.g., certain item types may restrict eligible methods)
-
Response is authoritative — the
available_instrumentsin theresponse_schemareflects the business's resolved selection for this specific checkout. Platforms MUST treat it as authoritative and MUST NOT attempt to use instrument types or apply constraints that contradict it.
Example:
| Source | available_instruments |
|---|---|
| Platform profile | [{type: "card", constraints: {properties: {brand: {enum: ["visa", "mastercard", "amex", "discover"]}}}}] |
| Business profile | [{type: "card", constraints: {properties: {brand: {enum: ["visa", "mastercard", "amex"]}}}}] |
| Response (resolved) | [{type: "card", constraints: {properties: {brand: {enum: ["visa", "mastercard", "amex"]}}}}] |
In this example, the business's PSP is not configured for Discover, so Discover is excluded from the response even though the platform supports it.
Defining the Schema¶
The schema field points to a JSON schema that defines handler-specific shapes.
Authors typically define each shape in its own file and reference them:
- Config — Configuration for platform/business declarations and runtime responses
- Instrument — The payment instrument structure returned to platforms
- Credential — The credential structure within instruments
Example Handler Schema:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/ucp/handlers/tokenizer/schema.json",
"title": "Tokenizer Handler Schema",
"description": "Schema for the com.example.tokenizer payment handler.",
"name": "com.example.tokenizer",
"version": "draft",
"$defs": {
"tokenizer_token": { "$ref": "types/tokenizer_token.json" },
"tokenizer_alt_token": { "$ref": "types/tokenizer_alt_token.json" },
"tokenizer_instrument": { "$ref": "types/tokenizer_instrument.json" },
"tokenizer_alt_instrument": { "$ref": "types/tokenizer_alt_instrument.json" },
"com.example.tokenizer": {
"payment_instrument": {
"title": "Tokenizer Payment Instrument",
"description": "Any instrument type supported by this handler.",
"oneOf": [
{ "$ref": "#/$defs/tokenizer_instrument" },
{ "$ref": "#/$defs/tokenizer_alt_instrument" }
]
},
"platform_schema": {
"title": "Tokenizer (Platform)",
"description": "Platform-level handler configuration for discovery.",
"allOf": [
{ "$ref": "https://ucp.dev/draft/schemas/payment_handler.json#/$defs/platform_schema" },
{
"properties": {
"config": {
"$ref": "types/platform_config.json",
"description": "Platform configuration for this handler."
}
}
}
]
},
"business_schema": {
"title": "Tokenizer (Business)",
"description": "Business-level handler configuration for discovery.",
"allOf": [
{ "$ref": "https://ucp.dev/draft/schemas/payment_handler.json#/$defs/business_schema" },
{
"properties": {
"config": {
"$ref": "types/business_config.json",
"description": "Business configuration for this handler."
}
}
}
]
},
"response_schema": {
"title": "Tokenizer (Response)",
"description": "Runtime handler configuration in checkout responses.",
"allOf": [
{ "$ref": "https://ucp.dev/draft/schemas/payment_handler.json#/$defs/response_schema" },
{
"properties": {
"config": {
"$ref": "types/response_config.json",
"description": "Runtime configuration for this handler."
}
}
}
]
}
}
}
}
Config Shapes¶
Each variant has its own config schema tailored to its context:
| Variant | Config File | Purpose |
|---|---|---|
| business_schema | types/business_config.json |
Business identity and merchant-specific settings |
| platform_schema | types/platform_config.json |
Platform identity and platform-level settings |
| response_schema | types/response_config.json |
Full runtime state: identities, tokenization specs |
Example types/business_config.json:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/ucp/handlers/tokenizer/types/business_config.json",
"title": "Tokenizer Business Config",
"type": "object",
"properties": {
"environment": {
"type": "string",
"enum": ["sandbox", "production"],
"default": "production"
},
"business_id": {
"type": "string",
"description": "Business identifier for this handler."
}
}
}
Example types/platform_config.json:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/ucp/handlers/tokenizer/types/platform_config.json",
"title": "Tokenizer Platform Config",
"type": "object",
"properties": {
"environment": {
"type": "string",
"enum": ["sandbox", "production"],
"default": "production"
},
"platform_id": {
"type": "string",
"description": "Platform identifier for this handler."
}
}
}
Example types/response_config.json:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/ucp/handlers/tokenizer/types/response_config.json",
"title": "Tokenizer Response Config",
"type": "object",
"properties": {
"api_version": { "type": "integer" },
"environment": {
"type": "string",
"enum": ["sandbox", "production"]
},
"business_id": {
"type": "string",
"description": "Business identifier for this handler."
},
"tokenization_specification": {
"type": "object",
"description": "Handler-specific tokenization settings.",
"properties": {
"type": { "type": "string" },
"parameters": { "type": "object" }
}
}
}
}
Instrument Shapes¶
Base Instrument Schemas:
| Schema | Description |
|---|---|
payment_instrument.json |
Base: id, handler_id, type, billing_address, credential, display |
card_payment_instrument.json |
Extends base with display: brand, last_digits, expiry, card art |
UCP provides base schemas for universal payment instruments like card. Spec
authors MAY extend any of the base instruments to add handler-specific
display data or customize the credential reference. Handlers MAY define
multiple instrument types for different payment flows.
Constraint Targets:
An instrument schema declares what its availability constraints may name in
$defs/constraint_target: a plain object of members and their types, never
carried in a payload. The handler's payment_instrument set binds each type
to the schema that owns its target.
card_payment_instrument.json
declares brand as a string, so
{ "properties": { "brand": { "enum": ["visa", "mastercard"] } } } names a
declared member and pins it to string values. The base Payment Handler validates
the grammar, so a malformed constraints fails everywhere; the target supplies
the meaning, so naming an undeclared member or pinning the wrong type is
reportable without the base dispatching on type. A handler extending an
instrument SHOULD extend that instrument's target rather than restate it.
Example types/tokenizer_instrument.json:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/ucp/handlers/tokenizer/types/tokenizer_instrument.json",
"title": "Tokenizer Card Instrument",
"description": "Card-based payment instrument for com.example.tokenizer.",
"$defs": {
"constraint_target": {
"title": "Tokenizer Card Constraint Target",
"description": "Extends the card target with tokenizer-specific members.",
"allOf": [
{ "$ref": "https://ucp.dev/draft/schemas/shopping/types/card_payment_instrument.json#/$defs/constraint_target" },
{
"type": "object",
"properties": {
"tokenization_type": {
"type": "string",
"description": "How the credential was tokenized (e.g., 'network_token', 'merchant_token')."
}
}
}
]
}
},
"allOf": [
{ "$ref": "https://ucp.dev/draft/schemas/shopping/types/card_payment_instrument.json" }
],
"type": "object",
"required": ["type"],
"properties": {
"type": { "const": "tokenizer_card" },
"credential": {
"oneOf": [
{ "$ref": "tokenizer_token.json" },
{ "$ref": "tokenizer_alt_token.json" }
]
},
"special_tokenizer_context": {
"type": "object",
"description": "Handler-specific context for tokenizer instruments."
}
}
}
Example types/tokenizer_alt_instrument.json:
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/ucp/handlers/tokenizer/types/tokenizer_alt_instrument.json",
"title": "Tokenizer Alt Instrument",
"description": "Alternative payment instrument for com.example.tokenizer.",
"allOf": [
{ "$ref": "https://ucp.dev/draft/schemas/shopping/types/payment_instrument.json" }
],
"type": "object",
"required": ["type"],
"properties": {
"type": { "const": "tokenizer_alt" },
"credential": {
"oneOf": [
{ "$ref": "tokenizer_token.json" },
{ "$ref": "tokenizer_alt_token.json" }
]
},
"special_tokenizer_context": {
"type": "object",
"description": "Handler-specific context for tokenizer instruments."
}
}
}
Credential Shapes¶
Base Credential Schemas:
| Schema | Description |
|---|---|
payment_credential.json |
Base: type discriminator only |
token_credential.json |
Token: type + token string |
pan_credential.json |
Raw FPAN, verified with cvc. Source only. |
network_token_credential.json |
Network token, verified with cryptogram |
UCP provides base schemas for universal payment credentials. Authors MAY extend these schemas to include handler-specific credential context. Handlers MAY define multiple credential types for different instrument flows.
The specification MUST define which credential types are accepted by the handler.
Important: If using token credentials, the schema MUST include an
expiration field (expiry, ttl, or similar) to ensure platforms know when to
refresh credentials.
Example types/tokenizer_token.json (expiring token):
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/ucp/handlers/tokenizer/types/tokenizer_token.json",
"title": "Tokenizer Card Token",
"description": "Card token credential for com.example.tokenizer.",
"allOf": [
{ "$ref": "https://ucp.dev/draft/schemas/shopping/types/token_credential.json" }
],
"type": "object",
"required": ["type", "token", "expiry"],
"properties": {
"type": {
"const": "tokenizer_card_token",
"description": "Credential type discriminator."
},
"expiry": {
"type": "string",
"format": "date-time",
"description": "Token expiration. Platforms must refresh before this time."
}
}
}
Example types/tokenizer_alt_token.json (alt token):
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://example.com/ucp/handlers/tokenizer/types/tokenizer_alt_token.json",
"title": "Tokenizer Alt Token",
"description": "Alt token credential for com.example.tokenizer, adding routing hints",
"allOf": [
{ "$ref": "https://ucp.dev/draft/schemas/shopping/types/token_credential.json" }
],
"type": "object",
"required": ["type", "token", "expiry"],
"properties": {
"type": {
"const": "tokenizer_alt_token",
"description": "Credential type discriminator."
},
"expiry": {
"type": "string",
"format": "date-time",
"description": "Token expiration. Platforms must refresh before this time."
},
"routing_hint": {
"type": "string",
"description": "Optional routing number hint."
}
}
}
Instrument Acquisition¶
Definition: The protocol a platform follows to acquire a payment instrument that can be submitted to the business's checkout.
Signature:
INSTRUMENT_ACQUISITION(
platform_prerequisites_output,
handler_declaration,
binding,
buyer_input
) → checkout_instrument
| Field | Description |
|---|---|
platform_prerequisites_output |
platform's prerequisites output (config), if prerequisites were required |
handler_declaration.config |
Handler-specific configuration from the business |
binding |
(See 2.6) Context for binding the credential to a specific checkout |
buyer_input |
Buyer's payment selection or credentials |
checkout_instrument |
The payment instrument to submit at checkout |
Payment handler specifications do NOT need to define a formal process for instrument acquisition. Instead, the specification SHOULD clearly document:
- How to apply the handler's
configto construct a validcheckout_instrument. - How to create an effective credential binding to the specific checkout and
business for usage, which is critical for security, based on the available
configandcheckout.
Payment Actions¶
A payment handler may require the Platform to perform additional work while the
Business processes an instrument. The Business returns that work in the
Checkout's actions map.
Handler authors have two options:
- Use the standard Payment Authentication extension. Handlers that need
device data collection or a 3DS challenge use
dev.ucp.shopping.payment_authentication, which defines thedev.ucp.payment.device_data_collectionanddev.ucp.payment.three_ds_challengeAction types. The handler specification states which types it can cause and any provider-specific trust or fallback requirements, such as allowed origins. - Define handler-specific Actions. When the standard types do not fit, the
handler author publishes a Checkout extension that declares its Action type
keys and
configshapes. Both the Business and Platform advertise that extension before those Actions are emitted.
For each handler-specific Action, document when it is emitted, the exact effect its type gates, how the Platform processes its config, how the Business observes its completion, whether processing the same occurrence is ever safe to retry, and its trust, failure, abandonment, and fallback behavior.
See Overview — Actions for the common envelope and Schema Authoring — Extension-Declared Action Types for the extension schema pattern.
Processing¶
Definition: The steps a participant (typically business or PSP) takes to process a received payment instrument and complete the transaction.
Signature:
| Field | Description |
|---|---|
identity |
The processing participant's PaymentIdentity |
checkout_instrument |
The instrument received from the platform |
binding |
The binding context for verification |
transaction_context |
Checkout totals, line items, etc. |
processing_result |
Success/failure with payment details |
Error Handling¶
The specification MUST define a mapping for common failures (e.g., 'Declined', 'Insufficient Funds', 'Network Error') to standard UCP Error definitions. This ensures the platform can render localized, consistent error messages to the buyer regardless of the underlying processor.
Key Definitions¶
| Term | Definition |
|---|---|
| Binding | A cryptographic or logical association of a payment instrument to a specific checkout transaction and business identity. This prevents replay attacks where a valid credential intended for Business A is intercepted and used at Business B. |
Specification Template¶
Handler specifications SHOULD use the standard template structure. Sections marked [REQUIRED] MUST be present; sections marked [CONDITIONAL] are required only when applicable.
Conformance Checklist for Spec Authors¶
Before publishing a payment handler specification, verify:
Structure¶
- Uses the standard template structure
- All [REQUIRED] sections are present
- [CONDITIONAL] sections are present when applicable
Participants¶
- All participants are listed
- Each participant's role is clearly described
- Note on "Business" vs "Merchant" terminology added if applicable
Prerequisites¶
- Prerequisites process is documented for each participant that requires it
- Onboarding inputs are specified
- Prerequisites output is described (identity + any additional config)
- Identity maps to
PaymentIdentitystructure (access_token)
Handler Declaration¶
- Identity schema is documented (base or extended)
- Configuration schema is documented (if applicable) and includes environment
- Instrument schema is documented (base or extended)
Instrument Acquisition¶
- Protocol steps are enumerated and clear
- Logical flow is mapped to actual protocol
- API calls or SDK usage is shown with examples
- Binding requirements are specified
- Checkout Payment Instrument creation and shape is well-defined
Payment Authentication Actions (if applicable)¶
- Every Action type is declared by a negotiated extension
- The gated effect, emission conditions, and sequencing are documented
- Instrument and handler association is unambiguous
- The allowed origins of any handler-operated Action surfaces are documented
- Unsupported, abandoned, expired, and failed fallbacks are documented
- Safe-retry conditions are defined, or retrying the same occurrence is forbidden
- Server-side outcome observation and pending-attempt cleanup are defined
Processing¶
- Processing steps are enumerated and clear
- Verification requirements are specified
- Error handling and mapping is addressed
Security¶
- Security requirements are listed
- Binding verification is required
- Credential handling guidance is provided
- Token expiry is defined (if applicable)
General¶
- Handler name follows reverse-DNS convention
- Version follows YYYY-MM-DD format
- All schema URLs match namespace authority
- References section includes all schemas
Best Practices¶
Follow these guidelines to create high-quality, maintainable handler specifications:
Schema Design¶
| Practice | Description |
|---|---|
| Extend, don't reinvent | Use allOf to compose base schemas. Don't redefine brand, last_digits, etc. |
| Use const for discriminators | Define credential.type as a const to identify credential types unambiguously. |
| Validate early | Publish schemas at stable URLs before finalizing the spec so implementers can validate. |
| Include Expiry | When designing token credentials, always include expiry or ttl. |
Documentation¶
| Practice | Description |
|---|---|
| Show, don't just tell | Include complete JSON examples for every schema and protocol step. |
| Document error cases | Specify what errors can occur and how participants should handle them. |
| Version independently | The handler version evolves independently of UCP core versions. |
Security¶
| Practice | Description |
|---|---|
| Require binding | Always tie credentials to a specific checkout via binding. |
| Minimize credential exposure | Design flows so raw credentials (PANs, etc.) touch as few systems as possible. |
| Specify token lifetimes | Document whether tokens are single-use, time-limited, or session-scoped. |
Maintainability¶
| Practice | Description |
|---|---|
| Host schemas at stable URLs | Schema URLs should not change; use versioned paths if needed. |
| Fail gracefully | Define clear error responses for common failure scenarios. |
| Link to examples | Reference existing handler specs and the Tokenization Guide for common flows. |
See Also¶
- Tokenization Guide — Guide for building tokenization payment handlers
- Google Pay Handler — Handler for Google Pay integration
- Shop Pay Handler — Handler for Shop Pay integration