Skip to content

[Proposal]: Platform Correlation Reference for Checkout and Order Webhook Events #413

@xiaoxuanz-hub

Description

@xiaoxuanz-hub

Summary

Introduce a platform_reference field — an opaque, platform-supplied string — that is set during checkout and persisted onto the resulting order. When the business sends order lifecycle webhook events, this reference is included, enabling the platform to correlate incoming order updates back to its internal user, session, or transaction records without maintaining a separate mapping of business-assigned checkout_id values.

Motivation

UCP is designed so that a platform (e.g., a shopping agent service) mediates between buyers and businesses (merchants). A single platform instance may serve many users across many businesses simultaneously. When a business sends an order status update via the orderEvent webhook, the platform must be able to efficiently determine:

  1. Which internal user/buyer session this order belongs to.
  2. Which internal transaction or conversation context originated the checkout.

Current State

Today, the order webhook payload includes:

  • id — the business's order identifier (unknown to the platform until order creation)
  • checkout_id — the business's checkout session identifier (assigned by the business, not the platform)

While checkout_id does link the order back to the checkout session, this linkage has a fundamental limitation: the platform did not assign this ID. The platform must:

  1. Receive the checkout_id from the business's response to create_checkout.
  2. Store a mapping: business_checkout_id → (user_id, session_id, internal_context).
  3. On every incoming webhook, look up order.checkout_id in this mapping.

This works but introduces fragility:

  • The platform must maintain and index a mapping table for every active checkout across every business.
  • If the platform loses this mapping (crash, redeployment, storage failure), correlation is permanently lost — there is no way to recover the link from the order payload alone.
  • Multi-platform architectures (e.g., platform with multiple service instances) must share this mapping state.
  • The checkout_id format and semantics are entirely business-controlled; the platform cannot embed any meaningful structure.

The Gap

There is no mechanism for the platform to pass its own opaque reference during checkout that the business is required to persist and echo back on all subsequent order events. This is a common pattern in payment and commerce protocols (e.g., Stripe's client_reference_id, PayPal's custom_id, Shopify's note_attributes).

Goals

  • Allow platforms to set an opaque reference string during checkout that is echoed back on all order webhook events.
  • Enable stateless or near-stateless correlation of webhook events to platform-internal records.
  • Minimize business implementation burden — the business stores the value and returns it, but does not need to interpret it.
  • Maintain backward compatibility — the field is optional. But it should be respected if provided.

Non-Goals

Detailed Design

1. Add platform_reference to the Checkout Schema

Add a new optional field platform_reference to checkout.json:

{
  "platform_reference": {
    "type": "string",
    "maxLength": 512,
    "description": "Opaque platform-supplied reference. Set by the platform at checkout completion to enable correlation of subsequent order events back to platform-internal records (user, session, transaction). The business MUST persist this value and include it on all order objects and webhook events derived from this checkout. The business MUST NOT interpret, modify, or depend on the structure of this value.",
    "ucp_request": {
      "create": "omit",
      "update": "omit",
      "complete": "optional"
    }
  }
}

Behavior:

  • The platform MAY set platform_reference on the complete_checkout request only. It is not accepted on create or update requests.
  • The business MUST persist the value and associate it with the resulting order.
  • The business MUST echo the value back in the complete checkout response.

2. Add platform_reference to the Order Schema

Add a new required field platform_reference to order.json (required when the originating checkout had one):

{
  "platform_reference": {
    "type": "string",
    "maxLength": 512,
    "description": "Platform-supplied correlation reference from the originating checkout session. Echoed verbatim by the business. Enables the platform to correlate order lifecycle events to internal records without maintaining external ID mappings.",
    "ucp_request": "omit"
  }
}

Behavior:

  • When an order is created from a checkout that had platform_reference set, the business MUST include the value verbatim on the order.
  • The value MUST NOT be modified by the business at any point in the order lifecycle.
  • The value is present on every webhook orderEvent payload since the full order object is sent.

3. Lifecycle Flow

Platform                           Business
   |                                  |
   |-- create_checkout -------------->|
   |   { line_items: [...] }          |
   |<---------- 201 checkout ---------|
   |   { id: "chk_xyz",              |
   |     status: "incomplete" }       |
   |                                  |
   |-- update_checkout(chk_xyz) ----->|
   |   { buyer: {...}, ... }          |
   |<---------- 200 checkout ---------|
   |                                  |
   |-- complete_checkout(chk_xyz) --->|
   |   { payment: {...},              |
   |     platform_reference: "pref_abc123" }|
   |<---------- 200 checkout ---------|
   |   { status: "completed",         |
   |     platform_reference: "pref_abc123", |
   |     order: { id: "ord_001" } }   |
   |                                  |
   |   ... time passes ...            |
   |                                  |
   |<-- orderEvent webhook -----------|
   |   { id: "ord_001",              |
   |     checkout_id: "chk_xyz",      |
   |     platform_reference: "pref_abc123", |
   |     fulfillment: { events: [...] } } |
   |                                  |
   |   Platform looks up "pref_abc123"|
   |   → user_id: "u_42",            |
   |     session_id: "sess_789"       |

4. What Platforms Can Encode

The value is opaque to the business. Platforms are free to encode whatever they need, for example:

  • A direct internal session ID: "sess_789"
  • A composite key: "u_42:sess_789:conv_101"
  • An encrypted/signed token containing user and session context
  • A lookup key into a distributed cache or database

The maxLength of 512 characters accommodates signed JWTs, composite keys, and other structured-but-opaque values while preventing unbounded storage burden on the business.


Alternatives Considered

A. Use attribution for correlation

The attribution field is an open key-value map, so platforms could theoretically stuff a reference into it. However:

  • attribution is semantically for campaign/referral tracking, not session correlation.
  • It is marked ucp_request: "omit" on orders (read-only snapshot), but importantly the business could interpret and filter attribution keys.
  • Overloading it conflates two distinct concerns.

B. Use signals for correlation

signals is for environmental metadata (IP, user agent). Using it for correlation would be a semantic mismatch and signals are not guaranteed to be echoed on orders.

C. Use a custom HTTP header

Headers are not persisted on the order object and would require separate correlation logic in the webhook path.

D. Require platforms to index checkout_id

This is the status quo. It works but creates the fragility and operational burden described in Motivation.

Risks and Mitigations

Security

The platform_reference is opaque and platform-controlled, so the business does not interpret it — low risk of injection or misuse. However, if a platform embeds sensitive data (user IDs, session tokens) in plaintext, a compromised business could correlate users across checkouts.

Mitigation: The specification SHOULD recommend that platforms use opaque, non-guessable values (UUIDs, encrypted/signed tokens) rather than raw internal identifiers. The business MUST treat the value as opaque and MUST NOT log, index, or process it beyond what is necessary for storage and echo-back.

Performance

One additional string field (max 512 bytes) per checkout and order — negligible storage and serialization cost. No new API calls or round-trips are introduced.

Mitigation: The maxLength: 512 cap prevents abuse and bounds the storage obligation on the business side.

Backward Compatibility

Fully backward compatible. The field is optional on checkout requests and conditionally present on orders. Existing integrations that do not set it see no change. Businesses that do not yet support it simply ignore the field (per additionalProperties: true on the checkout schema).

Mitigation: None needed — no breaking changes. No migration plan required.

Complexity

Minimal. Businesses persist one extra string and echo it back verbatim. No new endpoints, no new state machines, no conditional logic beyond "if present, store and return."

Mitigation: The field is deliberately opaque — the business does not need to validate, parse, or act on the value, keeping implementation effort trivial.

Test Plan

Unit Tests

  • Checkout schema validation: platform_reference accepted on complete_checkout request; rejected (or ignored) on create_checkout and update_checkout requests.
  • Checkout schema validation: platform_reference exceeding maxLength (512) is rejected with a structured error.
  • Order schema validation: platform_reference is present and matches the value from the originating checkout when one was provided.
  • Order schema validation: orders created from checkouts without platform_reference validate successfully with the field absent.
  • Webhook payload validation: orderEvent webhook body includes platform_reference verbatim when present on the order.
  • Existing fixtures without platform_reference continue to validate unchanged (backward compatibility).

Integration Tests

  • Full checkout flow with platform_reference: create_checkoutupdate_checkoutcomplete_checkout (with platform_reference: "test_ref_123") → verify the completed checkout response echoes platform_reference: "test_ref_123".
  • Order creation: after completing a checkout with platform_reference, the resulting order object contains the same platform_reference value verbatim.
  • Order creation without reference: completing a checkout without platform_reference produces an order with no platform_reference field — no default value injected.
  • Immutability: the business does not alter platform_reference across subsequent order updates or webhook events — the value remains identical to what was set at completion.

End-to-End Tests

  • Platform correlation flow: platform sets platform_reference at complete → business sends orderEvent webhook with fulfillment update → platform receives webhook and successfully correlates the order to the originating user and session using platform_reference alone.
  • Multi-business correlation: platform completes checkouts with distinct platform_reference values across two different businesses → webhook events from each business carry the correct, non-conflated reference.
  • UCP Playground / conformance harness: record full tool call sequences showing platform_reference round-tripping through complete → order → webhook without modification.

Graduation Criteria

Working Draft → Candidate:

  • Schema merged and documented (with Working Draft disclaimer).
  • Unit and integration tests are passing.
  • Initial documentation is written.
  • TC majority vote to advance.

Candidate → Stable:

  • Adoption feedback has been collected and addressed.
  • Full documentation and migration guides are published.
  • TC majority vote to advance.

Implementation History

  • [2026-05-05]: Proposal submitted.

Code of Conduct

  • I agree to follow this project's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions