Embedded Checkout Protocol

Overview

Embedded Checkout Protocol (ECP) enables a host to embed a business’s checkout interface, receive events as the buyer interacts, and delegate key user actions such as address and payment selection.

W3C Payment Request Alignment

ECP draws inspiration from W3C Payment Request API, adapting its mental model for embedded checkout scenarios:

ConceptW3C Payment RequestEmbedded Checkout
Initializationnew PaymentRequest()Load with continue_url
UI Readyshow() returns Promiseec.start notification
Payment Method Changepaymentmethodchange eventec.payment.change notification
Submit PaymentUser accepts → PaymentResponseDelegated ec.payment.credential_request
Completionresponse.complete()ec.complete notification

Discovery

ECP availability is signaled via service discovery. When a business advertises the embedded transport, all continue_url values support ECP:

{
  "services": {
    "dev.ucp.shopping": {
      "embedded": {
        "schema": "https://ucp.dev/services/shopping/embedded.openrpc.json"
      }
    }
  }
}

Loading Embedded Checkout

To initiate an ECP session, augment the continue_url with query parameters:

  • ec_version (string, REQUIRED): UCP version (format: YYYY-MM-DD)
  • ec_auth (string, OPTIONAL): Authentication token
  • ec_delegate (string, OPTIONAL): Comma-delimited list of delegations

Example:

https://example.com/checkout/abc123?ec_version=2026-01-11&ec_delegate=payment.credential,fulfillment.address_change

Delegations

Delegations allow the host to handle specific actions natively:

ec_delegate valueCorresponding message
payment.instruments_changeec.payment.instruments_change_request
payment.credentialec.payment.credential_request
fulfillment.address_changeec.fulfillment.address_change_request

Message Format

All ECP messages MUST use JSON-RPC 2.0 format:

{
  "jsonrpc": "2.0",
  "method": "ec.start",
  "params": {...},
  "id": "optional_request_id"
}

Core Messages

ec.ready (Handshake)

Establishes connection between host and Embedded Checkout:

{
  "jsonrpc": "2.0",
  "id": "ready_1",
  "method": "ec.ready",
  "params": {
    "delegate": ["payment.credential", "fulfillment.address_change"]
  }
}

Host response:

{
  "jsonrpc": "2.0",
  "id": "ready_1",
  "result": {
    "checkout": {
      "payment": {
        "instruments": [...]
      }
    }
  }
}

ec.start (Lifecycle)

Signals checkout is visible and ready for interaction:

{
  "jsonrpc": "2.0",
  "method": "ec.start",
  "params": {
    "checkout": {
      "id": "checkout_123",
      "status": "incomplete",
      "totals": [...],
      "line_items": [...]
    }
  }
}

ec.complete (Lifecycle)

Indicates successful checkout completion:

{
  "jsonrpc": "2.0",
  "method": "ec.complete",
  "params": {
    "checkout": {
      "id": "checkout_123",
      "order": {
        "id": "ord_99887766",
        "permalink_url": "https://merchant.com/orders/ord_99887766"
      }
    }
  }
}

ec.payment.credential_request (Delegation)

Requests a payment credential from the host:

{
  "jsonrpc": "2.0",
  "id": "payment_credential_request_1",
  "method": "ec.payment.credential_request",
  "params": {
    "checkout": {
      "id": "checkout_123",
      "payment": {
        "selected_instrument_id": "payment_instrument_123"
      }
    }
  }
}

Host response:

{
  "jsonrpc": "2.0",
  "id": "payment_credential_request_1",
  "result": {
    "checkout": {
      "payment": {
        "instruments": [
          {
            "id": "payment_instrument_123",
            "credential": {
              "type": "token",
              "token": "tok_123"
            }
          }
        ]
      }
    }
  }
}

Communication Channels

Web-Based Hosts

Use postMessage between host and embedded windows. Host MUST validate origin.

Native Hosts

Inject window.EmbeddedCheckoutProtocolConsumer global object:

{
  postMessage(message: string): void
}

Security

CSP Requirements

  • Business: Set frame-ancestors <host_origin>;
  • Host: Use appropriate frame-src or intermediate iframe

Iframe Sandbox

<iframe sandbox="allow-scripts allow-forms allow-same-origin"></iframe>

Credentialless Iframes

<iframe credentialless src="https://business.example.com/checkout"></iframe>

Error Codes

CodeDescription
abort_errorUser cancelled the interaction
security_errorOrigin validation failed
not_supported_errorPayment method not supported
invalid_state_errorHandshake out of order
not_allowed_errorMissing user activation

See Also