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
6 changes: 4 additions & 2 deletions docs/specification/cart-rest.md
Original file line number Diff line number Diff line change
Expand Up @@ -483,8 +483,10 @@ operations unless otherwise noted.
* **Idempotency-Key**: Operations that modify state **SHOULD** support
idempotency. When provided, the server **MUST**:
1. Store the key with the operation result for at least 24 hours.
2. Return the cached result for duplicate keys.
3. Return `409 Conflict` if the key is reused with different parameters.
2. Return the cached result for duplicate keys whose request body matches the original.
3. Return `409 Conflict` if the key is reused with a mismatched body.
See [Message Signatures — Idempotency Key Requirements](signatures.md#replay-protection)
for the full payload-matching contract.

## Protocol Mechanics

Expand Down
6 changes: 4 additions & 2 deletions docs/specification/checkout-rest.md
Original file line number Diff line number Diff line change
Expand Up @@ -1256,8 +1256,10 @@ operations unless otherwise noted.
* **Idempotency-Key**: Operations that modify state **SHOULD** support
idempotency. When provided, the server **MUST**:
1. Store the key with the operation result for at least 24 hours.
2. Return the cached result for duplicate keys.
3. Return `409 Conflict` if the key is reused with different parameters.
2. Return the cached result for duplicate keys whose request body matches the original.
3. Return `409 Conflict` if the key is reused with a mismatched body.
See [Message Signatures — Idempotency Key Requirements](signatures.md#replay-protection)
for the full payload-matching contract.

## Protocol Mechanics

Expand Down
16 changes: 15 additions & 1 deletion docs/specification/signatures.md
Original file line number Diff line number Diff line change
Expand Up @@ -483,9 +483,23 @@ Signature: sig1=:MEUCIQD...:
| **Entropy** | Minimum 128 bits (e.g., UUID v4, 22+ char alphanumeric) |
| **Uniqueness** | Per-client, per-operation type |
| **Server storage** | Minimum 24 hours, recommended 48 hours |
| **On duplicate** | Return cached response, do not re-execute |
| **On duplicate (matching payload)** | Return cached response, do not re-execute |
| **On duplicate (mismatched payload)** | Reject with `409 Conflict` (REST) / `-32000` (MCP); do not execute |
| **On storage failure** | Fail closed (reject request with 503) |

**Payload Matching:** Businesses **MUST** detect whether the payload of
a duplicate-key request matches the payload of the original by
comparing the SHA-256 hash of the raw body bytes — the same digest
RFC 9530 mandates as `Content-Digest`. When signing is in use, this
value is supplied in the `Content-Digest` header and the Intermediary
Warning above guarantees byte fidelity end-to-end; businesses persist
it alongside the idempotency key. For unsigned requests, businesses
compute the same digest from the received body bytes. Platforms
therefore **MUST** generate a fresh idempotency key whenever they
modify the request payload — including retries with modified payment
instruments, updated shipping addresses, swapped line items, or any
other change to the request body.

**Note:** The RFC 9421 `created` parameter is **OPTIONAL**. UCP handles replay
protection at the business layer through idempotency keys, not signature timestamps.
Key rotation (removing compromised keys from `signing_keys`) provides the mechanism
Expand Down
8 changes: 6 additions & 2 deletions docs/specification/split-payments.md
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,12 @@ MUST process each request as a fresh, full submission, without
reference to prior requests or responses.

> [!NOTE]
> **Idempotency & Correlation during Recovery Retries:**
> When retrying a partially authorized split payment with a modified set of payment instruments (e.g., replacing a declined card), the request payload changes and therefore **MUST** use a new idempotency key. Downstream systems cannot rely on the idempotency key to correlate the retry with previous partial authorizations; they must use the stable Checkout Session `id` to correlate and reconcile these distinct attempts.
> Each split payments submission is processed as a complete,
> self-contained request: a modified instrument set is a new submission,
> requiring a fresh [idempotency key](signatures.md#replay-protection).
> Split-payments state — including authorizations — does not persist
> between submissions; the unwind-on-failure requirement above
> enforces this.

**Per-instrument reporting:** when a split is incomplete or has failed,
the business MUST emit a `payment_failed` error for each failed
Expand Down
Loading