-
Notifications
You must be signed in to change notification settings - Fork 425
feat: Add Payment Authentication Actions #458
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
raginpirate
wants to merge
1
commit into
main
Choose a base branch
from
raginpirate/embedded-frame-action
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
208 changes: 208 additions & 0 deletions
208
docs/specification/payment-actions/device-data-collection.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,208 @@ | ||
| <!-- | ||
| Copyright 2026 UCP Authors | ||
|
|
||
| Licensed under the Apache License, Version 2.0 (the "License"); | ||
| you may not use this file except in compliance with the License. | ||
| You may obtain a copy of the License at | ||
|
|
||
| http://www.apache.org/licenses/LICENSE-2.0 | ||
|
|
||
| Unless required by applicable law or agreed to in writing, software | ||
| distributed under the License is distributed on an "AS IS" BASIS, | ||
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | ||
| See the License for the specific language governing permissions and | ||
| limitations under the License. | ||
| --> | ||
|
|
||
| # Payment Device Data Collection Action | ||
|
|
||
| This specification defines the device data collection Action type declared by | ||
| the [Payment Authentication extension](../payment-authentication.md): | ||
|
|
||
| ```text | ||
| dev.ucp.payment.device_data_collection | ||
| ``` | ||
|
|
||
| It asks the Platform to run a scoped, invisible browser-capable surface associated | ||
| with a payment instrument or attempt. | ||
|
|
||
| ## Purpose and Scope | ||
|
|
||
| Device data collection lets a Business, payment handler, PSP, or 3DS provider | ||
| collect device or browser data before payment processing continues. UCP does not | ||
| carry the collected data. The loaded surface sends provider-specific data directly | ||
| to the Business or payment provider through its own integration. | ||
|
|
||
| For EMV 3DS, this Action represents only the Platform-facing instruction to | ||
| mount the collection surface. UCP does not define how a Business maps ACS method | ||
| availability, method timeouts, or collection outcomes into EMVCo state such as | ||
| `threeDSCompInd`. If a provider or Business skips collection, including when an | ||
| ACS supplies no method URL, the Business does not emit this Action. | ||
|
|
||
| ## Emission and Gated Effect | ||
|
|
||
| A Business **MAY** emit this type from a Create, Update, or Complete Checkout | ||
| response after it can associate collection with a payment instrument and | ||
| negotiated payment handler. `config.payment_instrument_id` identifies that | ||
| instrument. | ||
|
|
||
| The Action gates advancement of the associated payment attempt while the | ||
| occurrence remains outstanding in the authoritative Checkout. A terminal surface | ||
| event starts reconciliation; it does not itself lift the gate or assert that | ||
| collection succeeded. If collection is merely an optimization that the Business | ||
| will not wait for, the Business **MUST NOT** emit an Action. | ||
|
|
||
| ## Runtime Shape | ||
|
|
||
| The Action is emitted under its type key: | ||
|
|
||
| <!-- ucp:example schema=shopping/payment_authentication def=dev.ucp.shopping.checkout extract=$.actions target=$.actions op=read --> | ||
| ```json | ||
| { | ||
| "actions": { | ||
| "dev.ucp.payment.device_data_collection": [ | ||
| { | ||
| "id": "ddc-1", | ||
| "config": { | ||
| "payment_instrument_id": "instrument_1", | ||
| "url": "https://payments.example.com/ucp/payment/ddc/session_123" | ||
| } | ||
| } | ||
| ] | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| The config shape is defined inline by the | ||
| [Payment Authentication extension schema](site:schemas/shopping/payment_authentication.json). | ||
|
|
||
| | Field | Type | Required | Notes | | ||
| | :---- | :--- | :------- | :---- | | ||
| | `payment_instrument_id` | string | ✓ | ID of the associated instrument in the containing Checkout. | | ||
| | `url` | string | ✓ | Absolute HTTPS URL for the invisible collection surface. | | ||
|
|
||
| The Business **SHOULD** provide a Business- or provider-operated wrapper URL that | ||
| owns any provider-specific POST, such as posting `threeDSMethodData` to an ACS | ||
| method URL. The Platform performs an ordinary navigation to `config.url`. | ||
|
|
||
| ## Platform Behavior | ||
|
|
||
| The Platform **MUST**: | ||
|
|
||
| 1. validate the URL according to the Payment Authentication contract, the | ||
| payment handler and instrument context, and Platform policy; | ||
| 2. load the URL in an isolated, invisible browser-capable surface; | ||
| 3. complete the `action.ready` handshake before allowing collection to begin; | ||
| 4. correlate embedded notifications with both this Action occurrence and the | ||
| mounted surface; and | ||
| 5. unmount the surface after `action.done`, `action.error`, load failure, or | ||
| timeout. | ||
|
|
||
| Mounting the surface **MUST** follow the shared | ||
| [Payment Authentication rendering contract](../payment-authentication.md#surface-rendering-and-notifications) | ||
| and [Embedded Protocol security requirements](../embedded-protocol.md#security). | ||
|
|
||
| On the web the surface is typically a hidden iframe. A native Platform may use | ||
| an isolated webview or equivalent browser surface. It must not be visible to the | ||
| Buyer or request Buyer interaction. | ||
|
|
||
| The Platform distinguishes only whether its surface finished or could not | ||
| continue. It does not determine whether device data was collected successfully, | ||
| whether an ACS method timed out, or whether 3DS authentication should proceed. | ||
|
|
||
| ## Embedded Notifications | ||
|
|
||
| After completing the shared | ||
| [`action.ready` handshake](../payment-authentication.md#ready-handshake), the | ||
| surface sends JSON-RPC 2.0 notifications defined by the | ||
| [payment Action embedded contract](../payment-authentication.md#surface-rendering-and-notifications). | ||
|
|
||
| ### Done | ||
|
|
||
| When the Platform-facing collection step is finished, the surface **MUST** send: | ||
|
|
||
| <!-- ucp:example schema=transports/jsonrpc def=request op=read --> | ||
| ```json | ||
| { | ||
| "jsonrpc": "2.0", | ||
| "method": "action.done", | ||
| "params": { | ||
| "id": "ddc-1" | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| The surface may send `action.done` when handler-owned logic determines that the | ||
| Platform should close the surface. The notification does not reveal whether | ||
| collection succeeded, was unavailable, was skipped, or mapped to a particular | ||
| provider completion indicator. | ||
|
|
||
| ### Error | ||
|
|
||
| If the surface cannot continue from the Platform-facing transport perspective, | ||
| it **MAY** send: | ||
|
|
||
| <!-- ucp:example schema=transports/jsonrpc def=request op=read --> | ||
| ```json | ||
| { | ||
| "jsonrpc": "2.0", | ||
| "method": "action.error", | ||
| "params": { | ||
| "id": "ddc-1", | ||
| "error": { | ||
| "ucp": { "version": "{{ ucp_version }}", "status": "error" }, | ||
| "messages": [ | ||
| { | ||
| "type": "error", | ||
| "code": "action_unavailable", | ||
| "content": "Device data collection could not start.", | ||
| "severity": "recoverable" | ||
| } | ||
| ] | ||
| } | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| Recommended surface-level codes are `action_unavailable` when initialization | ||
| fails, `action_expired` when the surface's session expired, and `action_failed` | ||
| for another terminal surface error. These are diagnostic codes, not EMV 3DS or | ||
| payment outcomes. A provider-domain timeout or unavailable method that the | ||
| handler can safely continue past should normally result in `action.done`, with | ||
| the Business and provider recording the domain outcome server-side. After either | ||
| notification, the Platform follows the shared Payment Authentication | ||
| reconciliation contract. | ||
|
|
||
| ## Deadline and Fallback | ||
|
|
||
| [EMV 3-D Secure Protocol and Core Functions v2.3.1.1](https://www.emvco.com/specifications/emv-3-d-secure-protocol-and-core-functions-specification-6/){ target="_blank" } | ||
| requires the 3DS Server to set `threeDSCompInd` to `N` when the 3DS Method does | ||
| not complete within five seconds (Req 315). That provider-domain timer begins | ||
| when the method is invoked and remains owned by the Business and provider; the | ||
| Platform **MUST NOT** derive it from the outer surface's load event. | ||
|
|
||
| The Platform applies a bounded outer-surface deadline defined by the handler or | ||
| Platform policy, measured from navigation and capped by Checkout `expires_at`. | ||
| That deadline controls only how long the Platform keeps the UCP surface mounted; | ||
| it does not set `threeDSCompInd` or another provider outcome. | ||
|
|
||
| If no valid `action.done` or `action.error` arrives before the outer deadline, | ||
| the Platform **MUST** unmount the surface, treat the interaction as timed out, | ||
| and follow the non-successful surface reconciliation path. It may unmount sooner | ||
| after load failure or a valid terminal notification. The Platform **MUST NOT** | ||
| remount the same Action type and `id`; an unchanged occurrence follows the | ||
| parent Checkout Actions fallback, handoff, and cancellation rules. | ||
|
|
||
| ## Security | ||
|
|
||
| The common [Payment Authentication security requirements](../payment-authentication.md#security-and-data-handling) | ||
| apply. In addition: | ||
|
|
||
| - The handler's trust policy **MUST** authorize the initial and redirect origins | ||
| before the Platform loads them. | ||
| - The surface **MUST NOT** receive Platform credentials or access Platform | ||
| storage. | ||
| - Provider payloads and collected device data **MUST NOT** be copied into the | ||
| Action, notification params, Checkout, or payment instrument. | ||
| - `action.done` and `action.error` are advisory surface signals. A later | ||
| Checkout response, based on Business/provider state, remains authoritative. | ||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.