Skip to content

Order Capability

  • Capability Name: dev.ucp.shopping.order

Overview

Orders represent confirmed transactions resulting from a successful checkout submission. They provide a complete record of what was purchased, how it will be delivered, and what has happened since order placement.

Key Concepts

Orders have three main components:

Line Items — what was purchased at checkout:

  • Includes current quantity counts (total, fulfilled)
  • Can change post-order (e.g. order edits, exchanges); MUST include all line items that ever existed on the order regardless of edits or alterations

Fulfillment — how items get delivered:

  • Expectations — buyer-facing promises about when/how items will arrive
  • Events (append-only log) — what actually happened (e.g. 👕 was shipped)

Adjustments — post-order events independent of fulfillment:

  • Typically money movements (refunds, returns, credits, disputes, cancellations)
  • Can be any post-order change
  • Can happen before, during, or after fulfillment
  • Businesses SHOULD append new entries rather than mutating existing ones; append-only ledger is preferred. Businesses that do not maintain adjustment history MAY perform in-place updates of existing entries (e.g. a single return adjustment can transition from pending to completed)

Data Model

Line Items

Line items reflect what was purchased at checkout and their current state:

  • Item details (product, price, quantity ordered)
  • Quantity counts and fulfillment status — original, total, and fulfilled are integer step counts of the item's inherited quantity_unit under the shared quantities and units contract; an absent quantity_unit means the quantities count whole items (each) at scale 0

All order lifecycle arithmetic over quantities operates on sale-basis step counts inherited from the item; other item characteristics do not enter that arithmetic. Business-recorded quantities — fulfillment events, adjustments, and revised totals — are bounded only by scale: a declared ordering increment binds Platform requests at cart and checkout and does not constrain what the Business records (a 0.25-lb ordering increment does not prevent recording an actual picked weight of 1.90 lb).

Fulfillment

Fulfillment tracks how items are delivered to the buyer.

Expectations

Expectations are buyer-facing groupings of items (e.g., "package 📦"). They represent:

  • What items are grouped together
  • Where they're going (destination)
  • How they're being delivered (method_type)
  • When they'll arrive (description, fulfillable_on)

Expectations can be split, merged, or adjusted post-order. For example:

  • Group everything by delivery date: "what is coming when"
  • Use a single expectation with a wide date range for flexibility
  • The goal is setting buyer expectations - for the best buyer experience

Fulfillment Events

Fulfillment Events are an append-only log tracking physical shipments:

  • Reference line items by ID and quantity
  • Include tracking information
  • Type is an open string field - businesses can use any values that make sense (common examples: processing, shipped, in_transit, delivered, failed_attempt, canceled, undeliverable, returned_to_sender)

Attribution

Businesses MAY surface a snapshot of the originating checkout's attribution on the order. Read-only on the order — agents do not write order.attribution. See Attribution for the underlying contract.

Policies

Businesses MAY surface a snapshot of the policies that applied at checkout on the order. See Policies for the underlying contract.

Adjustments

Adjustments are post-order events that exist independently of fulfillment:

  • Type is an open string field - businesses can use any values that make sense (typically money movements like refund, return, credit, price_adjustment, dispute, cancellation)
  • Can be any post-order change
  • Optionally link to line items (or order-level for things like shipping refunds)
  • Quantities are signed step counts and amounts are signed—negative for reductions (returns, refunds), positive for additions (exchanges)
  • Include totals breakdown when relevant
  • Can happen at any time regardless of fulfillment status

Schema

Order

Name Type Requirement Description
ucp any Required UCP metadata for order responses. No payment handlers needed post-purchase.
id string Required Unique order identifier.
label string Optional Human-readable label for identifying the order. MUST only be provided by the business.
checkout_id string Required Associated checkout ID for reconciliation.
permalink_url string Required Permalink to access the order on merchant site.
line_items Array[Order Line Item] Required Line items representing what was purchased — can change post-order via edits or exchanges.
fulfillment object Required Fulfillment data: buyer expectations and what actually happened.
adjustments Array[Adjustment] Optional Post-order events (refunds, returns, credits, disputes, cancellations, etc.) that exist independently of fulfillment.
currency string Required ISO 4217 currency code. MUST match the currency from the originating checkout session.
totals Totals Required Different totals for the order.
policies Array[Policy] Optional Snapshot of the policies that applied to the items at checkout, captured on the order as a durable record. applies_to targets are relative to the response root.
messages Array[Message] Optional Business outcome messages (errors, warnings, informational). Present when the business needs to communicate status or issues to the platform.
attribution Attribution Optional Snapshot of the attribution associated with the originating checkout. Read-only on the order.

Order Line Item

Line items reflect what was purchased at checkout and their current state.

Name Type Requirement Description
id string Required Line item identifier.
item Item Required Purchased item data, including identity, price, and sale basis.
quantity object Required Tracks the line item's original, current active, and fulfilled quantities. All three values use the same inherited item.quantity_unit. When item.quantity_unit is absent on an authoritative order response, each step is one whole item (each) under the shared default.
totals Array[Total Response] Required Line item totals breakdown.
status string Required Derived status: removed if quantity.total == 0, fulfilled if quantity.total > 0 and quantity.fulfilled == quantity.total, partial if quantity.total > 0 and quantity.fulfilled > 0, otherwise processing.
Enum: processing, partial, fulfilled, removed
parent_id string Optional Parent line item identifier for any nested structures.

Quantity Structure:

{
  "original": 3,   // Quantity from the original checkout
  "total": 3,      // Current total (may differ after edits/exchanges)
  "fulfilled": 2   // What has been fulfilled
}

When the item is measure-denominated these are step counts — for an item.quantity_unit of { "unit": "LBR", "scale": 2, "display_text": "lb" }, fulfilled: 50 means 0.50 lb fulfilled.

Status Derivation:

total and fulfilled are step counts in the same inherited item.quantity_unit; the derivation operates on those counts:

if (total == 0) → "removed"
else if (fulfilled == total) → "fulfilled"
else if (fulfilled > 0) → "partial"
else → "processing"

Expectation

Expectations are buyer-facing groupings representing when/how items will be delivered. They represent the current promise to the buyer and can be split, merged, or adjusted post-order.

Name Type Requirement Description
id string Required Expectation identifier.
line_items Array[object] Required Which line items and quantities are in this expectation.
method_type string Required Delivery method type. Well-known values: shipping, pickup, digital; additional values MAY be used.
destination Postal Address Required Delivery destination address.
description string Optional Human-readable delivery description (e.g., 'Arrives in 5-8 business days').
fulfillable_on string Optional When this expectation can be fulfilled: 'now' or ISO 8601 timestamp for future date (backorder, pre-order).

Fulfillment Event

Events are append-only records tracking actual shipments. The type field is an open string - businesses can use any values that make sense for their fulfillment process.

Name Type Requirement Description
id string Required Fulfillment event identifier.
occurred_at string Required RFC 3339 timestamp when this fulfillment event occurred.
type string Required Fulfillment event type. Common values include: processing (preparing to ship), shipped (handed to carrier), in_transit (in delivery network), delivered (received by buyer), failed_attempt (delivery attempt failed), canceled (fulfillment canceled), undeliverable (cannot be delivered), returned_to_sender (returned to merchant).
line_items Array[object] Required Which line items and quantities are fulfilled in this event.
tracking_number string Optional Carrier tracking number (required if type != processing).
tracking_url string Optional URL to track this shipment (required if type != processing).
carrier string Optional Carrier name (e.g., 'FedEx', 'USPS').
description string Optional Human-readable description of the shipment status or delivery information (e.g., 'Delivered to front door', 'Out for delivery').

Examples: processing, shipped, in_transit, delivered, failed_attempt, canceled, undeliverable, returned_to_sender, etc.

Adjustment

Adjustments are polymorphic events that exist independently of fulfillment. The type field is an open string - businesses can use any values that make sense to them.

Name Type Requirement Description
id string Required Adjustment event identifier.
type string Required Type of adjustment (open string). Typically money-related like: refund, return, credit, price_adjustment, dispute, cancellation. Can be any value that makes sense for the merchant's business.
occurred_at string Required RFC 3339 timestamp when this adjustment occurred.
status string Required Adjustment status.
Enum: pending, completed, failed
line_items Array[object] Optional Which line items and quantities are affected (optional).
totals Array[Total Response] Optional Adjustment totals breakdown. Signed values - negative for money returned to buyer (refunds, credits), positive for additional charges (exchanges).
description string Optional Human-readable reason or description (e.g., 'Defective item', 'Customer requested').

Examples: refund, return, credit, price_adjustment, dispute, cancellation, etc.

Example

{
  "ucp": {
    "version": "draft",
    "capabilities": {
      "dev.ucp.shopping.order": [{"version": "draft"}]
    }
  },
  "id": "order_abc123",
  "checkout_id": "checkout_xyz789",
  "permalink_url": "https://business.example.com/orders/abc123",
  "currency": "USD",
  "line_items": [
    {
      "id": "li_shoes",
      "item": { "id": "prod_shoes", "title": "Running Shoes", "price": 3000 },
      "quantity": { "original": 3, "total": 3, "fulfilled": 3 },
      "totals": [
        {"type": "subtotal", "amount": 9000},
        {"type": "total", "amount": 9000}
      ],
      "status": "fulfilled"
    },
    {
      "id": "li_shirts",
      "item": { "id": "prod_shirts", "title": "Cotton T-Shirt", "price": 2000 },
      "quantity": { "original": 2, "total": 2, "fulfilled": 0 },
      "totals": [
        {"type": "subtotal", "amount": 4000},
        {"type": "total", "amount": 4000}
      ],
      "status": "processing"
    }
  ],
  "fulfillment": {
    "expectations": [
      {
        "id": "exp_1",
        "line_items": [{ "id": "li_shoes", "quantity": 3 }],
        "method_type": "shipping",
        "destination": {
          "street_address": "123 Main St",
          "address_locality": "Austin",
          "address_region": "TX",
          "address_country": "US",
          "postal_code": "78701"
        },
        "description": "Arrives in 2-3 business days",
        "fulfillable_on": "now"
      },
      {
        "id": "exp_2",
        "line_items": [{ "id": "li_shirts", "quantity": 2 }],
        "method_type": "shipping",
        "destination": {
          "street_address": "123 Main St",
          "address_locality": "Austin",
          "address_region": "TX",
          "address_country": "US",
          "postal_code": "78701"
        },
        "description": "Backordered - ships Jan 15, arrives in 7-10 days",
        "fulfillable_on": "2025-01-15T00:00:00Z"
      }
    ],
    "events": [
      {
        "id": "evt_1",
        "occurred_at": "2025-01-08T10:30:00Z",
        "type": "delivered",
        "line_items": [{ "id": "li_shoes", "quantity": 3 }],
        "tracking_number": "123456789",
        "tracking_url": "https://fedex.com/track/123456789",
        "description": "Delivered to front door"
      }
    ]
  },
  "adjustments": [
    {
      "id": "adj_1",
      "type": "refund",
      "occurred_at": "2025-01-10T14:30:00Z",
      "status": "completed",
      "line_items": [{ "id": "li_shoes", "quantity": -1 }],
      "totals": [
        { "type": "total", "amount": -3000 }
      ],
      "description": "Defective item"
    }
  ],
  "totals": [
    { "type": "subtotal", "amount": 13000 },
    { "type": "fulfillment", "amount": 1200 },
    { "type": "tax", "amount": 1142 },
    { "type": "total", "amount": 15342 }
  ]
}

Example: goods sold by measure

An order for bananas sold by the pound (item.quantity_unit { "unit": "LBR", "scale": 2, "display_text": "lb", "increment": 25 }). Quantities are step counts: the Buyer ordered 1.50 lb (total: 150), of which 0.50 lb has shipped (fulfilled: 50), so the line is partial. A later return of 0.25 lb is recorded as an adjustment of -25 steps. Amounts are priced at $0.79/lb and rounded once — the line total is 79 × 1.50 = 118.5, rounded to 119, and the return credits 79 × 0.25 = 19.75, rounded to 20:

{
  "ucp": {
    "version": "draft",
    "capabilities": { "dev.ucp.shopping.order": [{"version": "draft"}] }
  },
  "id": "order_bananas_1",
  "checkout_id": "chk_bananas_1",
  "permalink_url": "https://business.example.com/orders/bananas1",
  "currency": "USD",
  "line_items": [
    {
      "id": "li_bananas",
      "item": {
        "id": "var_bananas",
        "title": "Bananas",
        "price": 79,
        "quantity_unit": { "unit": "LBR", "scale": 2, "display_text": "lb", "increment": 25 }
      },
      "quantity": { "original": 150, "total": 150, "fulfilled": 50 },
      "totals": [
        { "type": "subtotal", "amount": 119 },
        { "type": "total", "amount": 119 }
      ],
      "status": "partial"
    }
  ],
  "fulfillment": {
    "events": [
      {
        "id": "evt_1",
        "occurred_at": "2026-01-08T10:30:00Z",
        "type": "shipped",
        "line_items": [{ "id": "li_bananas", "quantity": 50 }],
        "tracking_number": "123456789",
        "tracking_url": "https://carrier.example/track/123456789",
        "description": "0.50 lb shipped"
      }
    ]
  },
  "adjustments": [
    {
      "id": "adj_1",
      "type": "return",
      "occurred_at": "2026-01-10T14:30:00Z",
      "status": "completed",
      "line_items": [{ "id": "li_bananas", "quantity": -25 }],
      "totals": [{ "type": "total", "amount": -20 }],
      "description": "Returned 0.25 lb"
    }
  ],
  "totals": [
    { "type": "subtotal", "amount": 119 },
    { "type": "total", "amount": 119 }
  ]
}

Example: count-sold, measure-priced settlement

Some items are sold by count but priced by measurement — apples at $2.00/lb, sold per each, with a nominal per-apple weight. Two bases are in play, and both travel: the sale basis governs quantity (whole apples, lifecycle arithmetic untouched), and the pricing basis — the line's echoed unit_price — carries the rate and nominal measure the charge is computed from. When the price settles against an actual measurement, the adjustment MUST carry the settled measure; its unit identity MUST match the pricing basis (no conversion), and a pure price settlement uses quantity: 0 so the count is untouched. (A settled measure is Business-recorded fact; Buyer-configured measurements that define item identity are a separate negotiated extension.)

A Buyer orders 3 apples at $0.80 each (nominal 0.40 lb × $2.00/lb; line total 240). The picker weighs the three apples at 1.14 lb against the nominal 1.20 lb, and the settlement is fully verifiable from the order alone: nominal steps 3 × 40 = 120, settled 114, delta 6 steps × 200 × 10^-2 = 12 — the -12 adjustment checks out in integer arithmetic:

{
  "ucp": {
    "version": "draft",
    "capabilities": { "dev.ucp.shopping.order": [{"version": "draft"}] }
  },
  "id": "order_apples_1",
  "checkout_id": "chk_apples_1",
  "permalink_url": "https://business.example.com/orders/apples1",
  "currency": "USD",
  "line_items": [
    {
      "id": "li_apples",
      "item": {
        "id": "var_apple",
        "title": "Honeycrisp Apple",
        "price": 80,
        "unit_price": {
          "amount": 200,
          "currency": "USD",
          "measure": { "value": 40, "scale": 2, "unit": "LBR", "display_text": "lb" },
          "reference": { "value": 1, "unit": "LBR", "display_text": "lb" }
        }
      },
      "quantity": { "original": 3, "total": 3, "fulfilled": 3 },
      "totals": [
        { "type": "subtotal", "amount": 240 },
        { "type": "total", "amount": 240 }
      ],
      "status": "fulfilled"
    }
  ],
  "fulfillment": {
    "events": [
      {
        "id": "evt_1",
        "occurred_at": "2026-01-14T09:15:00Z",
        "type": "shipped",
        "line_items": [{ "id": "li_apples", "quantity": 3 }],
        "description": "Picked 3 apples, 1.14 lb total"
      }
    ]
  },
  "adjustments": [
    {
      "id": "adj_1",
      "type": "price_adjustment",
      "occurred_at": "2026-01-14T09:15:00Z",
      "status": "completed",
      "line_items": [
        {
          "id": "li_apples",
          "quantity": 0,
          "measure": { "value": 114, "scale": 2, "unit": "LBR", "display_text": "lb" }
        }
      ],
      "totals": [{ "type": "total", "amount": -12 }],
      "description": "Settled to actual picked weight of 1.14 lb"
    }
  ],
  "totals": [
    { "type": "subtotal", "amount": 240 },
    { "type": "total", "amount": 240 }
  ]
}

The count lifecycle never moves — fulfilled == total holds on whole apples — while the money reconciles to the measured reality, and every number needed to verify the credit is on the order itself.

Example: catch-weight reconciliation

For weighed goods, the picked weight routinely differs from the ordered weight. The difference is a commercial fact, not a numeric error: the Business records the actual pick and reconciles the difference with an adjustment that moves money together with quantity. No tolerance comparison is involved; the status derivation operates on exact step counts throughout.

A Buyer orders 2.00 lb of the same bananas at $0.79/lb, sold in quarter-pound increments (quantity 200, line total 79 × 2.00 = 158). The picker weighs out 1.90 lb — an off-increment fact, recorded as-is, because the increment binds Platform ordering, not Business records. The fulfillment event records the actual 190 steps, and a price_adjustment of -10 steps reconciles total to the actual pick with its price delta (79 × 0.10 = 7.9, rounded once to 8). fulfilled == total then holds exactly (190 == 190) and the line derives fulfilled:

{
  "ucp": {
    "version": "draft",
    "capabilities": { "dev.ucp.shopping.order": [{"version": "draft"}] }
  },
  "id": "order_bananas_2",
  "checkout_id": "chk_bananas_2",
  "permalink_url": "https://business.example.com/orders/bananas2",
  "currency": "USD",
  "line_items": [
    {
      "id": "li_bananas",
      "item": {
        "id": "var_bananas",
        "title": "Bananas",
        "price": 79,
        "quantity_unit": { "unit": "LBR", "scale": 2, "display_text": "lb", "increment": 25 }
      },
      "quantity": { "original": 200, "total": 190, "fulfilled": 190 },
      "totals": [
        { "type": "subtotal", "amount": 158 },
        { "type": "total", "amount": 158 }
      ],
      "status": "fulfilled"
    }
  ],
  "fulfillment": {
    "events": [
      {
        "id": "evt_1",
        "occurred_at": "2026-01-12T09:15:00Z",
        "type": "shipped",
        "line_items": [{ "id": "li_bananas", "quantity": 190 }],
        "description": "Picked 1.90 lb"
      }
    ]
  },
  "adjustments": [
    {
      "id": "adj_1",
      "type": "price_adjustment",
      "occurred_at": "2026-01-12T09:15:00Z",
      "status": "completed",
      "line_items": [{ "id": "li_bananas", "quantity": -10 }],
      "totals": [{ "type": "total", "amount": -8 }],
      "description": "Adjusted to actual picked weight of 1.90 lb"
    }
  ],
  "totals": [
    { "type": "subtotal", "amount": 158 },
    { "type": "total", "amount": 158 }
  ]
}

Scopes

The Order capability defines the following well-known scopes for user-authenticated access:

Scope Description
dev.ucp.shopping.order:read Read access to the user's orders — Get Order on resources owned by the authenticated user.
dev.ucp.shopping.order:manage Post-purchase operations on the user's orders — cancellation, returns, and other modifications.

Scope declaration, derivation, and rules for extending this set with custom scopes are defined in Identity Linking — Scopes.

Operations

The order entity is a current-state snapshot: the authoritative latest state of the order at the time of retrieval or delivery. Businesses MUST return the full order entity on every response. The same schema is used for both synchronous retrieval (this section) and asynchronous event delivery (see Events).

The permalink_url is the authoritative reference for the full order experience - timeline, post-purchase operations, returns. The API provides programmatic access to current state for conversational and operational use cases.

Operation Method Endpoint Description
Get Order GET /orders/{id} Platform retrieves current order state.

For transport-specific details, see REST Binding, and MCP Binding

Get Order

Returns the current-state snapshot of an order.

Authorization

The business MUST authenticate requests to order data before returning a response, using any supported UCP mechanism - API keys, OAuth 2.0, mutual TLS, or HTTP Message Signatures (see Identity and Authentication). The authentication method determines which orders are accessible to the caller:

Authentication Accessible Orders
Platform credentials Orders originated by the platform
Buyer authorization Orders owned by the buyer, subject to the granted OAuth scopes

Platform credentials (API key, signatures, OAuth client credentials) - businesses MAY allow access for orders the platform originated. The platform provided buyer and payment information during the checkout flow, observed the order confirmation, and is retrieving the latest state of an order it already has context for.

Buyer authorization - the platform obtains buyer authorization via Identity Linking with the necessary scopes, or a similar mechanism. This grants access to the buyer's orders regardless of which platform originated them.

Businesses MAY define additional access policies (e.g., trusted partner agreements), enforce data availability constraints (e.g., retention windows, regulatory erasure), and omit or redact optional fields from the response based on context, business policy, or other requirements - independently of authorization.

Error Responses

When the business cannot return an order, the response returns an error that includes a messages array describing the outcome:

Order not found:

{
  "ucp": {
    "version": "draft",
    "status": "error",
    "capabilities": {
      "dev.ucp.shopping.order": [{"version": "draft"}]
    }
  },
  "messages": [
    {
      "type": "error",
      "code": "not_found",
      "severity": "unrecoverable",
      "content": "Order not found."
    }
  ]
}

Not authorized:

{
  "ucp": {
    "version": "draft",
    "status": "error",
    "capabilities": {
      "dev.ucp.shopping.order": [{"version": "draft"}]
    }
  },
  "messages": [
    {
      "type": "error",
      "code": "unauthorized",
      "severity": "unrecoverable",
      "content": "Not authorized to access this order."
    }
  ]
}

Guidelines

Platform:

  • MUST include UCP-Agent header with profile URL on all requests
  • SHOULD rely on webhooks (see Events) as the primary order update channel and use Get Order for reconciliation or on-demand retrieval
  • SHOULD treat order data as ephemeral and discard it when no longer needed for active commerce flows

Business:

  • MUST authenticate requests to order data before returning a response (see Authorization)

Events

Businesses push order lifecycle updates to the platform via webhooks. The payload is the same current-state snapshot described in Operations — the full order entity.

Event Method Endpoint Description
Order Event Webhook POST Platform-provided URL Business sends order lifecycle events to the platform.

Order Event Webhook

Businesses POST order events to a webhook URL provided by the platform during partner onboarding. The URL format is platform-specific.

Headers follow Standard Webhooks; except for request signing, which follows RFC 9421. See Message Signatures for more details.

Required Headers:

Header Description
Webhook-Timestamp Event occurrence timestamp (unix)
Webhook-Id Unique event identifier

Inputs

Name Type Requirement Description
ucp any Required UCP metadata for order responses. No payment handlers needed post-purchase.
id string Required Unique order identifier.
label string Optional Human-readable label for identifying the order. MUST only be provided by the business.
checkout_id string Required Associated checkout ID for reconciliation.
permalink_url string Required Permalink to access the order on merchant site.
line_items Array[Order Line Item] Required Line items representing what was purchased — can change post-order via edits or exchanges.
fulfillment object Required Fulfillment data: buyer expectations and what actually happened.
adjustments Array[Adjustment] Optional Post-order events (refunds, returns, credits, disputes, cancellations, etc.) that exist independently of fulfillment.
totals Totals Required Different totals for the order.
messages Array[Message] Optional Business outcome messages (errors, warnings, informational). Present when the business needs to communicate status or issues to the platform.

Output

Name Type Requirement Description
ucp Ucp Required

Webhook URL Configuration

The platform provides its webhook URL in the order capability's config field during capability negotiation. The business discovers this URL from the platform's profile and uses it to send order lifecycle events.

Platform's order capability configuration.

Name Type Requirement Description
webhook_url string Required URL where merchant sends order lifecycle events (webhooks).

Example:

{
  "dev.ucp.shopping.order": [
    {
      "version": "draft",
      "spec": "https://ucp.dev/draft/specification/shopping/order",
      "schema": "https://ucp.dev/draft/schemas/shopping/order.json",
      "config": {
        "webhook_url": "https://platform.example.com/webhooks/ucp/orders"
      }
    }
  ]
}

Webhook Signature Verification

Webhook payloads MUST be signed by the business and verified by the platform to ensure authenticity and integrity. Signatures follow the Message Signatures specification using the REST binding (RFC 9421).

Required Headers:

Header Description
UCP-Agent Business profile URL (RFC 8941 Dictionary)
Signature-Input Describes signed components
Signature Contains the signature value
Content-Digest Body digest (RFC 9530)

Example Webhook Request:

POST /webhooks/ucp/orders HTTP/1.1
Host: platform.example.com
Content-Type: application/json
UCP-Agent: profile="https://merchant.example/.well-known/ucp"
Content-Digest: sha-256=:X48E9q...:
Signature-Input: sig1=("@method" "@authority" "@path" "content-digest" "content-type");keyid="merchant-2026"
Signature: sig1=:MEUCIQDTxNq8h7LGHpvVZQp1iHkFp9+3N8Mxk2zH1wK4YuVN8w...:

{"id":"order_abc123","event_id":"evt_123","created_time":"2026-01-15T12:00:00Z",...}

Signing (Business)

  1. Compute SHA-256 digest of the raw request body and set Content-Digest header
  2. Build signature base per RFC 9421
  3. Sign using a key from keys in the business's UCP profile
  4. Set Signature-Input and Signature headers

See Message Signatures - REST Request Signing for complete algorithm.

Verification (Platform)

Authentication (signature verification):

  1. Parse Signature-Input to extract keyid and signed components
  2. Fetch business's UCP profile from /.well-known/ucp (cache as appropriate)
  3. Locate key in keys with matching kid
  4. Verify Content-Digest matches SHA-256 of raw body
  5. Reconstruct signature base and verify signature

See Message Signatures - REST Request Verification for complete algorithm.

Authorization (order ownership):

After verifying the signature, the platform MUST confirm the signer is authorized to send events for the referenced order:

  1. Extract the order ID from the webhook payload
  2. Verify the order was created with this business (profile URL matches)
  3. Reject webhooks where the signer's profile doesn't match the order's business

This prevents a malicious business from sending fake events for another business's orders, even with a valid signature.

Key Rotation

See Message Signatures - Key Rotation for zero-downtime key rotation procedures.

Guidelines

Platform:

  • MUST respond quickly with a 2xx HTTP status code to acknowledge webhook receipt; process events asynchronously after responding

Business:

  • MUST include UCP-Agent header with profile URL for signer identification
  • MUST sign all webhook payloads per the Message Signatures specification using RFC 9421 headers (Signature, Signature-Input, Content-Digest)
  • MUST send "Order created" event with fully populated order entity
  • MUST send full order entity on updates (not incremental deltas)
  • MUST retry failed webhook deliveries

Entities

Item

Name Type Requirement Description
id string Required The product identifier, often the SKU, required to resolve the product details associated with this line item. Should be recognized by both the Platform, and the Business.
title string Required Product title.
price Amount Required Unit price in ISO 4217 minor units. Price is the amount per one whole quantity_unit.unit (for example, per lb or per hour); when quantity_unit is absent, it is per each.
quantity_unit Quantity Unit Optional Sale basis this item's quantity is denominated in. On an authoritative Business response, absence encodes the default each machine identity (C62, 0); the Business MUST include this descriptor for every non-each response. On Platform requests, omission makes no assertion: the Business interprets quantity using the item's authoritative sale basis. If the Platform includes this descriptor, it asserts the unit-descriptor machine identity. The Business MUST compare that machine identity (unit, effective scale), ignore display_text and increment, and resolve a mismatch by conversion surfaced as a visible line revision with a warning, or by rejection with a recoverable business outcome; silent reinterpretation is forbidden. An explicit C62 descriptor at effective scale 0 matches an authoritative basis represented by an absent descriptor.
unit_price Unit Price Optional Pricing basis for this item. On an authoritative Business response, the Business MUST include unit_price on every line whose pricing basis differs from its sale basis (for example, priced per pound but sold per each); presence on a line marks the rate as transactional rather than display-only. When the pricing basis is the sale basis, item.price fully denominates the charge and this field MAY be omitted.
image_url string Optional Product image URI.

Postal Address

Name Type Requirement Description
extended_address string Optional An address extension such as an apartment number, C/O or alternative name.
street_address string Optional The street address.
address_locality string Optional The locality in which the street address is, and which is in the region. For example, Mountain View.
address_region string Optional The region in which the locality is, and which is in the country. Required for applicable countries (i.e. state in US, province in CA). For example, California or another appropriate first-level Administrative division.
address_country string Optional The country. Recommended to be in 2-letter ISO 3166-1 alpha-2 format, for example "US". For backward compatibility, a 3-letter ISO 3166-1 alpha-3 country code such as "SGP" or a full country name such as "Singapore" can also be used.
postal_code string Optional The postal code. For example, 94043.
first_name string Optional Optional. First name of the contact associated with the address.
last_name string Optional Optional. Last name of the contact associated with the address.
phone_number string Optional Optional. Phone number of the contact associated with the address.

Response

Capability reference in responses. Only name/version required to confirm active capabilities.

Name Type Requirement Description
version string Required Entity version in YYYY-MM-DD format.
spec string Optional URL to human-readable specification document.
schema string Optional URL to JSON Schema defining this entity's structure and payloads.
id string Optional Unique identifier for this entity instance. Used to disambiguate when multiple instances exist.
config object Optional Entity-specific configuration. Structure defined by each entity's schema.
extends OneOf[string, array] Optional Parent capability(s) this extends. Present for extensions, absent for root capabilities. Use array for multi-parent extensions.

Total

Name Type Requirement Description
type string Required Cost category. Well-known values: subtotal, items_discount, discount, fulfillment, tax, fee, total. Businesses MAY use additional values.
display_text string Optional Text to display against the amount. Should reflect appropriate method (e.g., 'Shipping', 'Delivery').
amount Signed Amount Required Monetary amount in the currency's minor unit as defined by ISO 4217. Refer to the currency's exponent to determine minor-to-major ratio (e.g., 2 for USD, 0 for JPY, 3 for KWD). May be negative — the sign is intrinsic to the value (e.g., discounts are negative, charges are positive).

UCP Response Order Schema

UCP metadata for order responses. No payment handlers needed post-purchase.

Name Type Requirement Description
version string Required Version identifier in YYYY-MM-DD format.
map_order object Optional Preferred key-traversal order for sibling registry fields inside the root ucp envelope (services, capabilities, and payment_handlers).
status string Optional Application-level status of the UCP operation.
Enum: success, error
services object Optional Service registry keyed by reverse-domain name.
capabilities object Optional Capability registry keyed by reverse-domain name.
payment_handlers object Optional Payment handler registry keyed by reverse-domain name.
capabilities any Optional