Skip to content

Getting Started with UCP

This guide will walk you through building a basic Universal Commerce Protocol (UCP) server. We provide examples for both Python (FastAPI) and Node.js (Express) using the official Python SDK and TypeScript SDK.

We will implement a simple checkout server that allows a platform to initiate a checkout session and retrieve it.

Prerequisites

  • Python 3.10 or higher installed.
  • Basic familiarity with FastAPI and Pydantic.
  • We recommend using uv for package management.
  • Node.js 18 or higher installed.
  • Basic familiarity with Express and Zod.

Project Setup

Create a new directory and initialize the project:

mkdir ucp-quickstart-python
cd ucp-quickstart-python
uv init

Add the required dependencies. ucp-sdk contains the Pydantic models generated from UCP schemas:

Note

The Python SDK package is registered as ucp-sdk on PyPI, but is imported as ucp_sdk (with an underscore) in your Python code.

uv add fastapi uvicorn ucp-sdk

Create a new directory and initialize the project:

mkdir ucp-quickstart-nodejs
cd ucp-quickstart-nodejs
npm init -y

Configure your package.json to use ES Modules by adding "type": "module".

Add the required dependencies. @ucp-js/sdk contains the TypeScript types and Zod schemas:

npm install express uuid @ucp-js/sdk
npm install --save-dev typescript @types/express @types/node tsx

Initialize TypeScript configuration:

npx tsc --init

Implementing the Server

We will implement the server step-by-step. The server needs to handle:

  1. Create Checkout (POST /checkout-sessions): Receives desired items and returns a checkout session with totals and available payment handlers.
  2. Get Checkout (GET /checkout-sessions/{id}): Allows the platform to poll the session status.

High-Level Flow

Here is how the components interact during the checkout process:

%%{init: {'sequence': {'actorMargin': 90, 'messageMargin': 45}}}%%
sequenceDiagram
    autonumber
    participant Platform as "Platform"
    participant Server as "Checkout Server (Your App)"
    participant DB as "In-Memory DB"

    Note over Platform,Server: Create Checkout Session
    Platform->>+Server: POST /checkout-sessions (with Items and Headers)
    Note over Server: Validate, Calculate Totals, and Advertise Payment Handlers
    Server->>DB: Store Session
    Server-->>-Platform: 201 Created (Checkout Response)

    Note over Platform,Server: Retrieve Checkout Session (Polling)
    Platform->>+Server: GET /checkout-sessions/{id} (with Headers)
    Server->>DB: Fetch Session
    Server-->>-Platform: 200 OK (Checkout Response)

How it fits into the E2E Flow

In a complete UCP integration, the flow follows these phases:

  1. Discovery: The Platform discovers your UCP endpoints (like /checkout-sessions) by fetching your UCP Discovery Profile at /.well-known/ucp.
  2. Create Checkout (Implemented in this guide): The Platform initiates the checkout session with the items the user wants to buy.
  3. Update Checkout: The Platform updates the checkout session with buyer details (e.g., shipping address, email) to calculate final taxes and shipping options.
  4. Complete Checkout: The Platform submits the payment credentials to finalize the order.

This guide focuses on step 2 (Create Checkout) and the subsequent retrieval of the checkout session state.

1. Imports and Setup

Initialize the application and define an in-memory database to store sessions.

# main.py
import uuid
from typing import Annotated
from fastapi import FastAPI, Header, HTTPException, status

# Import UCP SDK models
from ucp_sdk.models.schemas.ucp import ResponseCheckoutSchema
from ucp_sdk.models.schemas.shopping.checkout import Checkout
from ucp_sdk.models.schemas.shopping.checkout_create_request import CheckoutCreateRequest
from ucp_sdk.models.schemas.shopping.types.line_item import LineItem
from ucp_sdk.models.schemas.shopping.types.item import Item
from ucp_sdk.models.schemas.common.types.totals import Total
from ucp_sdk.models.schemas.common.types.link import Link
from ucp_sdk.models.schemas.common.types.available_payment_instrument import AvailablePaymentInstrument
from ucp_sdk.models.schemas.payment_handler import ResponseSchema as PaymentHandlerResponse

# Initialize FastAPI app
app = FastAPI(title="UCP Quickstart Server")

# Simple in-memory database
checkout_sessions = {}
// server.ts
import express from 'express';
import { v4 as uuidv4 } from 'uuid';

// Import validation schemas from JS SDK
import {
  CheckoutCreateRequestSchema,
  CheckoutResponseSchema,
  type CheckoutResponse
} from '@ucp-js/sdk';

// Initialize Express app
const app = express();
app.use(express.json());

// Simple in-memory database
const checkoutSessions: Record<string, CheckoutResponse> = {};

2. Create Checkout Endpoint (Route & Header Validation)

Define the endpoint to create a checkout session. UCP requires Idempotency-Key and UCP-Agent headers.

# main.py
@app.post(
    "/checkout-sessions",
    response_model=Checkout,
    status_code=status.HTTP_201_CREATED,
    response_model_exclude_none=True
)
async def create_checkout(
    body: CheckoutCreateRequest,
    idempotency_key: Annotated[str, Header(alias="Idempotency-Key")],
    ucp_agent: Annotated[str, Header(alias="UCP-Agent")]
):
    """Create a new UCP checkout session."""
    # Note: In a production environment, you must use the Idempotency-Key
    # to prevent duplicate processing of the same request.

    # Generate a unique checkout session ID
    session_id = f"chk_{uuid.uuid4().hex[:10]}"
// server.ts
app.post('/checkout-sessions', (req, res) => {
  // 1. Validate required UCP headers
  const idempotencyKey = req.header('Idempotency-Key');
  const ucpAgent = req.header('UCP-Agent');

  if (!idempotencyKey || !ucpAgent) {
    return res.status(400).json({
      error: 'Missing required headers (Idempotency-Key, UCP-Agent)'
    });
  }

  // 2. Validate request body against UCP schema using Zod
  const validation = CheckoutCreateRequestSchema.safeParse(req.body);
  if (!validation.success) {
    return res.status(400).json({ errors: validation.error.errors });
  }

  const body = validation.data;

  // Generate a unique checkout session ID
  const sessionId = `chk_${uuidv4().replace(/-/g, '').substring(0, 10)}`;

Note

If the required UCP headers are missing, FastAPI (Python) will automatically return an HTTP 422 Unprocessable Entity error due to its built-in validation. In our Express (Node.js) implementation, we manually return an HTTP 400 Bad Request error. For simplicity, this quickstart returns plain JSON errors (such as {"error": "..."} or FastAPI's {"detail": "..."}) for missing headers, validation failures, and 404 responses; production servers must return the specification's standard error format (see Error Responses and Core Specification — Error Handling).

3. Business Logic (Process Items & Calculate Totals)

Process the incoming line items, resolve their prices, and calculate the subtotal, tax, and total. Prices are always in minor units (e.g., cents for USD).

# main.py
    # Map input line items to output line items with pricing
    output_line_items = []
    subtotal = 0
    tax = 0

    for index, item_req in enumerate(body.line_items):
        # Mock product database lookup
        # In production, perform real-time inventory verification and stock
        # reservation here (catalog availability signals are advisory and can drift).
        price = 2500  # $25.00 in minor units (cents)
        title = f"Flower Bouquet {item_req.item.id}"
        item_subtotal = price * item_req.quantity
        item_tax = int(item_subtotal * 0.08)  # 8% tax
        item_total = item_subtotal + item_tax

        subtotal += item_subtotal
        tax += item_tax

        output_line_items.append(
            LineItem(
                id=f"li_{index}",
                item=Item(id=item_req.item.id, title=title, price=price),
                quantity=item_req.quantity,
                totals=[
                    Total(type="subtotal", amount=item_subtotal),
                    Total(type="tax", amount=item_tax),
                    Total(type="total", amount=item_total)
                ]
            )
        )

    total = subtotal + tax
// server.ts
  // Map input line items to output line items with pricing
  const outputLineItems = body.line_items.map((item, index) => {
    // Mock product database lookup
    // In production, perform real-time inventory verification and stock
    // reservation here (catalog availability signals are advisory and can drift).
    const price = 2500; // $25.00 in minor units (cents)
    const title = `Flower Bouquet ${item.item.id}`;
    const itemSubtotal = price * item.quantity;
    const itemTax = Math.floor(itemSubtotal * 0.08); // 8% tax
    const itemTotal = itemSubtotal + itemTax;

    return {
      id: `li_${index}`,
      item: { id: item.item.id, title, price },
      quantity: item.quantity,
      totals: [
        { type: 'subtotal', amount: itemSubtotal },
        { type: 'tax', amount: itemTax },
        { type: 'total', amount: itemTotal }
      ]
    };
  });

  // Calculate order totals from line items
  const subtotal = outputLineItems.reduce((acc, item) => {
    const subtotalEntry = item.totals.find(t => t.type === 'subtotal');
    return acc + (subtotalEntry ? subtotalEntry.amount : 0);
  }, 0);
  const tax = outputLineItems.reduce((acc, item) => {
    const taxEntry = item.totals.find(t => t.type === 'tax');
    return acc + (taxEntry ? taxEntry.amount : 0);
  }, 0);
  const total = subtotal + tax;

4. UCP Response Construction

Construct the UCP metadata block, advertising supported payment handlers, and assemble the final checkout response.

Capability Negotiation

In production, a business uses the UCP-Agent header to resolve the platform's profile, calculates the intersection of supported capabilities, and returns the active negotiated set in capabilities. For simplicity in this quickstart, full capability negotiation is omitted. See Discovery & Capability Negotiation for details.

# main.py
    # Configure available payment handlers.
    # We advertise support for a generic mock payment handler.
    payment_handlers = {
        "com.example.mock_pay": [
            PaymentHandlerResponse(
                id="mock_pay_handler_1",
                version="2026-08-25",
                available_instruments=[
                    AvailablePaymentInstrument(type="mock_instrument")
                ]
            )
        ]
    }

    # Construct UCP protocol metadata
    # (In production, populate active capabilities from UCP-Agent negotiation)
    ucp_metadata = ResponseCheckoutSchema(
        version="2026-08-25",
        status="success",
        payment_handlers=payment_handlers
    )

    # Assemble the final Checkout payload
    checkout = Checkout(
        ucp=ucp_metadata,
        id=session_id,
        status="incomplete",
        currency="USD",
        line_items=output_line_items,
        totals=[
            Total(type="subtotal", amount=subtotal),
            Total(type="tax", amount=tax),
            Total(type="total", amount=total)
        ],
        links=[
            Link(type="terms_of_service", url="https://example.com/terms"),
            Link(type="privacy_policy", url="https://example.com/privacy")
        ]
    )

    # Save to database and return
    checkout_sessions[session_id] = checkout
    return checkout
// server.ts
  // Configure available payment handlers.
  // We advertise support for a generic mock payment handler.
  const ucpMetadata = {
    version: '2026-08-25',
    status: 'success' as const,
    capabilities: {}, // In production, populate via capability negotiation from UCP-Agent
    payment_handlers: {
      'com.example.mock_pay': [
        {
          id: 'mock_pay_handler_1',
          version: '2026-08-25',
          available_instruments: [
            { type: 'mock_instrument' }
          ]
        }
      ]
    }
  };

  // Assemble the final Checkout payload
  const checkout: CheckoutResponse = {
    ucp: ucpMetadata,
    id: sessionId,
    status: 'incomplete',
    currency: 'USD',
    line_items: outputLineItems,
    totals: [
      { type: 'subtotal', amount: subtotal },
      { type: 'tax', amount: tax },
      { type: 'total', amount: total }
    ],
    links: [
      { type: 'terms_of_service', url: 'https://example.com/terms' },
      { type: 'privacy_policy', url: 'https://example.com/privacy' }
    ]
  };

  // Validate output matches CheckoutResponse schema before sending
  const outputValidation = CheckoutResponseSchema.safeParse(checkout);
  if (!outputValidation.success) {
    console.error('Output validation failed:', outputValidation.error);
    return res.status(500).json({ error: 'Internal server error' });
  }

  // Save to database and return
  checkoutSessions[sessionId] = checkout;
  res.status(201).json(checkout);
});

5. Get Checkout Endpoint

Implement the retrieval route so the platform can fetch the checkout state. Per UCP Header Requirements, UCP requires the UCP-Agent header on all requests (not just mutating operations like create, update, or complete).

# main.py
@app.get(
    "/checkout-sessions/{id}",
    response_model=Checkout,
    response_model_exclude_none=True
)
async def get_checkout(
    id: str,
    ucp_agent: Annotated[str, Header(alias="UCP-Agent")]
):
    """Retrieve an existing checkout session."""
    if id not in checkout_sessions:
        raise HTTPException(status_code=404, detail="Checkout session not found")
    return checkout_sessions[id]
// server.ts
app.get('/checkout-sessions/:id', (req, res) => {
  // 1. Validate required UCP headers
  const ucpAgent = req.header('UCP-Agent');
  if (!ucpAgent) {
    return res.status(400).json({
      error: 'Missing required header (UCP-Agent)'
    });
  }

  const session = checkoutSessions[req.params.id];
  if (!session) {
    return res.status(404).json({ error: 'Checkout session not found' });
  }
  res.json(session);
});

const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});

Running the Server

Start the server using Uvicorn:

uv run uvicorn main:app --port 8080 --reload

Add a start script to your package.json:

"scripts": {
  "start": "tsx server.ts"
}

Start the server:

npm start

Your server is now running at http://127.0.0.1:8080 (Python) or http://127.0.0.1:3000 (Node.js).


Testing the Server

You can test your server using curl.

1. Create a Checkout Session

Send a POST request to create a checkout session with one item:

curl -X POST http://127.0.0.1:8080/checkout-sessions \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: test-key-123" \
  -H "UCP-Agent: profile=\"https://platform.example/profile\"" \
  -d '{
    "line_items": [
      {
        "item": {
          "id": "prod_roses"
        },
        "quantity": 2
      }
    ]
  }'
curl -X POST http://127.0.0.1:3000/checkout-sessions \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: test-key-123" \
  -H "UCP-Agent: profile=\"https://platform.example/profile\"" \
  -d '{
    "line_items": [
      {
        "item": {
          "id": "prod_roses"
        },
        "quantity": 2
      }
    ]
  }'

You should receive a response containing the UCP metadata, calculated totals, and the configured payment handler:

{
  "ucp": {
    "version": "2026-08-25",
    "status": "success",
    "payment_handlers": {
      "com.example.mock_pay": [
        {
          "version": "2026-08-25",
          "id": "mock_pay_handler_1",
          "available_instruments": [
            {
              "type": "mock_instrument"
            }
          ]
        }
      ]
    }
  },
  "id": "chk_...",
  "line_items": [
    {
      "id": "li_0",
      "item": {
        "id": "prod_roses",
        "title": "Flower Bouquet prod_roses",
        "price": 2500
      },
      "quantity": 2,
      "totals": [
        {
          "type": "subtotal",
          "amount": 5000
        },
        {
          "type": "tax",
          "amount": 400
        },
        {
          "type": "total",
          "amount": 5400
        }
      ]
    }
  ],
  "status": "incomplete",
  "currency": "USD",
  "totals": [
    {
      "type": "subtotal",
      "amount": 5000
    },
    {
      "type": "tax",
      "amount": 400
    },
    {
      "type": "total",
      "amount": 5400
    }
  ],
  "links": [
    {
      "type": "terms_of_service",
      "url": "https://example.com/terms"
    },
    {
      "type": "privacy_policy",
      "url": "https://example.com/privacy"
    }
  ]
}

2. Retrieve the Checkout Session

Retrieve the session using the id returned from the previous step:

curl "http://127.0.0.1:8080/checkout-sessions/<replace-with-your-checkout-id>" \
  -H "UCP-Agent: profile=\"https://platform.example/profile\""
curl "http://127.0.0.1:3000/checkout-sessions/<replace-with-your-checkout-id>" \
  -H "UCP-Agent: profile=\"https://platform.example/profile\""

Full File Reference

If you want to verify your code, expand the section below to see the complete files.

Complete Code Reference

main.py

# main.py
import uuid
from typing import Annotated
from fastapi import FastAPI, Header, HTTPException, status

# Import UCP SDK models
from ucp_sdk.models.schemas.ucp import ResponseCheckoutSchema
from ucp_sdk.models.schemas.shopping.checkout import Checkout
from ucp_sdk.models.schemas.shopping.checkout_create_request import CheckoutCreateRequest
from ucp_sdk.models.schemas.shopping.types.line_item import LineItem
from ucp_sdk.models.schemas.shopping.types.item import Item
from ucp_sdk.models.schemas.common.types.totals import Total
from ucp_sdk.models.schemas.common.types.link import Link
from ucp_sdk.models.schemas.common.types.available_payment_instrument import AvailablePaymentInstrument
from ucp_sdk.models.schemas.payment_handler import ResponseSchema as PaymentHandlerResponse

# Initialize FastAPI app
app = FastAPI(title="UCP Quickstart Server")

# Simple in-memory database
checkout_sessions = {}

@app.post(
    "/checkout-sessions",
    response_model=Checkout,
    status_code=status.HTTP_201_CREATED,
    response_model_exclude_none=True
)
async def create_checkout(
    body: CheckoutCreateRequest,
    idempotency_key: Annotated[str, Header(alias="Idempotency-Key")],
    ucp_agent: Annotated[str, Header(alias="UCP-Agent")]
):
    """Create a new UCP checkout session."""
    # Note: In a production environment, you must use the Idempotency-Key
    # to prevent duplicate processing of the same request.

    # Generate a unique checkout session ID
    session_id = f"chk_{uuid.uuid4().hex[:10]}"

    # Map input line items to output line items with pricing
    output_line_items = []
    subtotal = 0
    tax = 0

    for index, item_req in enumerate(body.line_items):
        # Mock product database lookup
        # In production, perform real-time inventory verification and stock
        # reservation here (catalog availability signals are advisory and can drift).
        price = 2500  # $25.00 in minor units (cents)
        title = f"Flower Bouquet {item_req.item.id}"
        item_subtotal = price * item_req.quantity
        item_tax = int(item_subtotal * 0.08)  # 8% tax
        item_total = item_subtotal + item_tax

        subtotal += item_subtotal
        tax += item_tax

        output_line_items.append(
            LineItem(
                id=f"li_{index}",
                item=Item(id=item_req.item.id, title=title, price=price),
                quantity=item_req.quantity,
                totals=[
                    Total(type="subtotal", amount=item_subtotal),
                    Total(type="tax", amount=item_tax),
                    Total(type="total", amount=item_total)
                ]
            )
        )

    total = subtotal + tax

    # Configure available payment handlers.
    # We advertise support for a generic mock payment handler.
    payment_handlers = {
        "com.example.mock_pay": [
            PaymentHandlerResponse(
                id="mock_pay_handler_1",
                version="2026-08-25",
                available_instruments=[
                    AvailablePaymentInstrument(type="mock_instrument")
                ]
            )
        ]
    }

    # Construct UCP protocol metadata
    # (In production, populate active capabilities from UCP-Agent negotiation)
    ucp_metadata = ResponseCheckoutSchema(
        version="2026-08-25",
        status="success",
        payment_handlers=payment_handlers
    )

    # Assemble the final Checkout payload
    checkout = Checkout(
        ucp=ucp_metadata,
        id=session_id,
        status="incomplete",
        currency="USD",
        line_items=output_line_items,
        totals=[
            Total(type="subtotal", amount=subtotal),
            Total(type="tax", amount=tax),
            Total(type="total", amount=total)
        ],
        links=[
            Link(type="terms_of_service", url="https://example.com/terms"),
            Link(type="privacy_policy", url="https://example.com/privacy")
        ]
    )

    # Save to database and return
    checkout_sessions[session_id] = checkout
    return checkout

@app.get(
    "/checkout-sessions/{id}",
    response_model=Checkout,
    response_model_exclude_none=True
)
async def get_checkout(
    id: str,
    ucp_agent: Annotated[str, Header(alias="UCP-Agent")]
):
    """Retrieve an existing checkout session."""
    if id not in checkout_sessions:
        raise HTTPException(status_code=404, detail="Checkout session not found")
    return checkout_sessions[id]

server.ts

// server.ts
import express from 'express';
import { v4 as uuidv4 } from 'uuid';

// Import validation schemas from JS SDK
import {
  CheckoutCreateRequestSchema,
  CheckoutResponseSchema,
  type CheckoutResponse
} from '@ucp-js/sdk';

// Initialize Express app
const app = express();
app.use(express.json());

// Simple in-memory database
const checkoutSessions: Record<string, CheckoutResponse> = {};

app.post('/checkout-sessions', (req, res) => {
  // 1. Validate required UCP headers
  const idempotencyKey = req.header('Idempotency-Key');
  const ucpAgent = req.header('UCP-Agent');

  if (!idempotencyKey || !ucpAgent) {
    return res.status(400).json({
      error: 'Missing required headers (Idempotency-Key, UCP-Agent)'
    });
  }

  // 2. Validate request body against UCP schema using Zod
  const validation = CheckoutCreateRequestSchema.safeParse(req.body);
  if (!validation.success) {
    return res.status(400).json({ errors: validation.error.errors });
  }

  const body = validation.data;

  // Generate a unique checkout session ID
  const sessionId = `chk_${uuidv4().replace(/-/g, '').substring(0, 10)}`;

  // Map input line items to output line items with pricing
  const outputLineItems = body.line_items.map((item, index) => {
    // Mock product database lookup
    // In production, perform real-time inventory verification and stock
    // reservation here (catalog availability signals are advisory and can drift).
    const price = 2500; // $25.00 in minor units (cents)
    const title = `Flower Bouquet ${item.item.id}`;
    const itemSubtotal = price * item.quantity;
    const itemTax = Math.floor(itemSubtotal * 0.08); // 8% tax
    const itemTotal = itemSubtotal + itemTax;

    return {
      id: `li_${index}`,
      item: { id: item.item.id, title, price },
      quantity: item.quantity,
      totals: [
        { type: 'subtotal', amount: itemSubtotal },
        { type: 'tax', amount: itemTax },
        { type: 'total', amount: itemTotal }
      ]
    };
  });

  // Calculate order totals from line items
  const subtotal = outputLineItems.reduce((acc, item) => {
    const subtotalEntry = item.totals.find(t => t.type === 'subtotal');
    return acc + (subtotalEntry ? subtotalEntry.amount : 0);
  }, 0);
  const tax = outputLineItems.reduce((acc, item) => {
    const taxEntry = item.totals.find(t => t.type === 'tax');
    return acc + (taxEntry ? taxEntry.amount : 0);
  }, 0);
  const total = subtotal + tax;

  // Configure available payment handlers.
  // We advertise support for a generic mock payment handler.
  const ucpMetadata = {
    version: '2026-08-25',
    status: 'success' as const,
    capabilities: {}, // In production, populate via capability negotiation from UCP-Agent
    payment_handlers: {
      'com.example.mock_pay': [
        {
          id: 'mock_pay_handler_1',
          version: '2026-08-25',
          available_instruments: [
            { type: 'mock_instrument' }
          ]
        }
      ]
    }
  };

  // Assemble the final Checkout payload
  const checkout: CheckoutResponse = {
    ucp: ucpMetadata,
    id: sessionId,
    status: 'incomplete',
    currency: 'USD',
    line_items: outputLineItems,
    totals: [
      { type: 'subtotal', amount: subtotal },
      { type: 'tax', amount: tax },
      { type: 'total', amount: total }
    ],
    links: [
      { type: 'terms_of_service', url: 'https://example.com/terms' },
      { type: 'privacy_policy', url: 'https://example.com/privacy' }
    ]
  };

  // Validate output matches CheckoutResponse schema before sending
  const outputValidation = CheckoutResponseSchema.safeParse(checkout);
  if (!outputValidation.success) {
    console.error('Output validation failed:', outputValidation.error);
    return res.status(500).json({ error: 'Internal server error' });
  }

  // Save to database and return
  checkoutSessions[sessionId] = checkout;
  res.status(201).json(checkout);
});

app.get('/checkout-sessions/:id', (req, res) => {
  // 1. Validate required UCP headers
  const ucpAgent = req.header('UCP-Agent');
  if (!ucpAgent) {
    return res.status(400).json({
      error: 'Missing required header (UCP-Agent)'
    });
  }

  const session = checkoutSessions[req.params.id];
  if (!session) {
    return res.status(404).json({ error: 'Checkout session not found' });
  }
  res.json(session);
});

const PORT = 3000;
app.listen(PORT, () => {
  console.log(`Server is running on port ${PORT}`);
});


Next Steps

To build a fully compliant UCP server, you will also need to:

  • Implement the checkout update endpoint (PUT /checkout-sessions/{id}) to handle buyer information updates (like shipping address).
  • Implement the checkout completion endpoint (POST /checkout-sessions/{id}/complete) to process the payment instrument provided by the platform.
  • Advertise your service using a UCP Discovery Profile at /.well-known/ucp.
  • Run the conformance suite from the UCP Conformance repository against your server to verify protocol compliance.

For a complete reference implementation, check out the UCP Samples repository.