This document specifies the REST binding for the Cart Capability.
Businesses advertise REST transport availability through their UCP profile at
/.well-known/ucp.
{
"ucp": {
"version": "{{ ucp_version }}",
"services": {
"dev.ucp.shopping": [
{
"version": "{{ ucp_version }}",
"spec": "https://ucp.dev/{{ ucp_version }}/specification/overview",
"transport": "rest",
"schema": "https://ucp.dev/{{ ucp_version }}/services/shopping/rest.openapi.json",
"endpoint": "https://business.example.com/ucp/v1"
}
]
},
"capabilities": {
"dev.ucp.shopping.checkout": [
{
"version": "{{ ucp_version }}",
"spec": "https://ucp.dev/{{ ucp_version }}/specification/checkout",
"schema": "https://ucp.dev/{{ ucp_version }}/schemas/shopping/checkout.json"
}
],
"dev.ucp.shopping.cart": [
{
"version": "{{ ucp_version }}",
"spec": "https://ucp.dev/{{ ucp_version }}/specification/cart",
"schema": "https://ucp.dev/{{ ucp_version }}/schemas/shopping/cart.json"
}
]
},
"payment_handlers": {}
}
}All UCP REST endpoints are relative to the business's base URL, which is
discovered through the UCP profile at /.well-known/ucp. The endpoint for the
cart capability is defined in the rest.endpoint field of the business profile.
- Request:
application/json - Response:
application/json
All request and response bodies MUST be valid JSON as specified in RFC 8259{ target="_blank" }.
All REST endpoints MUST be served over HTTPS with minimum TLS version 1.3.
| Operation | Method | Endpoint | Description |
|---|---|---|---|
| Create Cart | POST |
/carts |
Create a cart session. |
| Get Cart | GET |
/carts/{id} |
Get a cart session. |
| Update Cart | PUT |
/carts/{id} |
Update a cart session. |
| Cancel Cart | POST |
/carts/{id}/cancel |
Cancel a cart session. |
{{ schema_fields('cart_create_req', 'cart') }}
{{ schema_fields('cart_resp', 'cart') }}
=== "Request"
<!-- ucp:example schema=shopping/cart op=create direction=request -->
```json
POST /carts HTTP/1.1
UCP-Agent: profile="https://platform.example/profile"
Content-Type: application/json
{
"line_items": [
{
"item": {
"id": "item_123"
},
"quantity": 2
}
],
"context": {
"address_country": "US",
"address_region": "CA",
"postal_code": "94105"
}
}
```
=== "Response"
<!-- ucp:example schema=shopping/cart op=read -->
```json
HTTP/1.1 201 Created
Content-Type: application/json
{
"ucp": {
"version": "{{ ucp_version }}",
"capabilities": {
"dev.ucp.shopping.checkout": [{"version": "{{ ucp_version }}"}],
"dev.ucp.shopping.cart": [{"version": "{{ ucp_version }}"}]
}
},
"id": "cart_abc123",
"line_items": [
{
"id": "li_1",
"item": {
"id": "item_123",
"title": "Red T-Shirt",
"price": 2500
},
"quantity": 2,
"totals": [
{"type": "subtotal", "amount": 5000},
{"type": "total", "amount": 5000}
]
}
],
"currency": "USD",
"totals": [
{
"type": "subtotal",
"amount": 5000
},
{
"type": "total",
"amount": 5000,
"display_text": "Estimated total (taxes calculated at checkout)"
}
],
"continue_url": "https://business.example.com/checkout?cart=cart_abc123",
"expires_at": "2026-01-16T12:00:00Z"
}
```
=== "Error Response"
All items out of stock — no cart resource is created:
<!-- ucp:example schema=common/types/error_response op=read -->
```json
HTTP/1.1 200 OK
Content-Type: application/json
{
"ucp": { "version": "{{ ucp_version }}", "status": "error" },
"messages": [
{
"type": "error",
"code": "out_of_stock",
"content": "All requested items are currently out of stock",
"severity": "unrecoverable"
}
],
"continue_url": "https://merchant.com/"
}
```
id(String, required): The cart session ID (path parameter).
{{ schema_fields('cart_resp', 'cart') }}
=== "Request"
```http
GET /carts/{id} HTTP/1.1
UCP-Agent: profile="https://platform.example/profile"
```
=== "Response"
<!-- ucp:example schema=shopping/cart op=read -->
```json
HTTP/1.1 200 OK
Content-Type: application/json
{
"ucp": {
"version": "{{ ucp_version }}",
"capabilities": {
"dev.ucp.shopping.checkout": [{"version": "{{ ucp_version }}"}],
"dev.ucp.shopping.cart": [{"version": "{{ ucp_version }}"}]
}
},
"id": "cart_abc123",
"line_items": [
{
"id": "li_1",
"item": {
"id": "item_123",
"title": "Red T-Shirt",
"price": 2500
},
"quantity": 2,
"totals": [
{"type": "subtotal", "amount": 5000},
{"type": "total", "amount": 5000}
]
}
],
"currency": "USD",
"totals": [
{
"type": "subtotal",
"amount": 5000
},
{
"type": "total",
"amount": 5000
}
],
"continue_url": "https://business.example.com/checkout?cart=cart_abc123",
"expires_at": "2026-01-16T12:00:00Z"
}
```
=== "Not Found"
<!-- ucp:example schema=common/types/error_response op=read -->
```json
HTTP/1.1 200 OK
Content-Type: application/json
{
"ucp": {
"version": "{{ ucp_version }}",
"status": "error",
"capabilities": {
"dev.ucp.shopping.cart": [{"version": "{{ ucp_version }}"}]
}
},
"messages": [
{
"type": "error",
"code": "not_found",
"content": "Cart not found or has expired",
"severity": "unrecoverable"
}
],
"continue_url": "https://merchant.com/"
}
```
id(String, required): The cart session ID (path parameter).
{{ schema_fields('cart_update_req', 'cart') }}
{{ schema_fields('cart_resp', 'cart') }}
=== "Request"
<!-- ucp:example schema=shopping/cart op=update direction=request -->
```json
PUT /carts/{id} HTTP/1.1
UCP-Agent: profile="https://platform.example/profile"
Content-Type: application/json
{
"id": "cart_abc123",
"line_items": [
{
"item": {
"id": "item_123"
},
"id": "li_1",
"quantity": 3
},
{
"item": {
"id": "item_456"
},
"id": "li_2",
"quantity": 1
}
],
"context": {
"address_country": "US",
"address_region": "CA",
"postal_code": "94105"
}
}
```
=== "Response"
<!-- ucp:example schema=shopping/cart op=read -->
```json
HTTP/1.1 200 OK
Content-Type: application/json
{
"ucp": {
"version": "{{ ucp_version }}",
"capabilities": {
"dev.ucp.shopping.checkout": [{"version": "{{ ucp_version }}"}],
"dev.ucp.shopping.cart": [{"version": "{{ ucp_version }}"}]
}
},
"id": "cart_abc123",
"line_items": [
{
"id": "li_1",
"item": {
"id": "item_123",
"title": "Red T-Shirt",
"price": 2500
},
"quantity": 3,
"totals": [
{"type": "subtotal", "amount": 7500},
{"type": "total", "amount": 7500}
]
},
{
"id": "li_2",
"item": {
"id": "item_456",
"title": "Blue Jeans",
"price": 7500
},
"quantity": 1,
"totals": [
{"type": "subtotal", "amount": 7500},
{"type": "total", "amount": 7500}
]
}
],
"currency": "USD",
"totals": [
{
"type": "subtotal",
"amount": 15000
},
{
"type": "total",
"amount": 15000
}
],
"continue_url": "https://business.example.com/checkout?cart=cart_abc123",
"expires_at": "2026-01-16T12:00:00Z"
}
```
id(String, required): The cart session ID (path parameter).
{{ schema_fields('cart_resp', 'cart') }}
=== "Request"
<!-- ucp:example schema=shopping/cart op=cancel direction=request -->
```json
POST /carts/{id}/cancel HTTP/1.1
UCP-Agent: profile="https://platform.example/profile"
Content-Type: application/json
{}
```
=== "Response"
<!-- ucp:example schema=shopping/cart op=read -->
```json
HTTP/1.1 200 OK
Content-Type: application/json
{
"ucp": {
"version": "{{ ucp_version }}",
"capabilities": {
"dev.ucp.shopping.checkout": [{"version": "{{ ucp_version }}"}],
"dev.ucp.shopping.cart": [{"version": "{{ ucp_version }}"}]
}
},
"id": "cart_abc123",
"line_items": [
{
"id": "li_1",
"item": {
"id": "item_123",
"title": "Red T-Shirt",
"price": 2500
},
"quantity": 2,
"totals": [
{"type": "subtotal", "amount": 5000},
{"type": "total", "amount": 5000}
]
}
],
"currency": "USD",
"totals": [
{
"type": "subtotal",
"amount": 5000
},
{
"type": "total",
"amount": 5000
}
],
"continue_url": "https://business.example.com/checkout?cart=cart_abc123"
}
```
The following headers are defined for the HTTP binding and apply to all operations unless otherwise noted.
{{ header_fields('create_cart', 'rest.openapi.json') }}
- UCP-Agent: All requests MUST include the
UCP-Agentheader containing the platform profile URI using Dictionary Structured Field syntax (RFC 8941{target="_blank"}). Format:profile="https://platform.example/profile". - Idempotency-Key: Operations that modify state SHOULD support
idempotency. When provided, the server MUST:
- Store the key with the operation result for at least 24 hours.
- Return the cached result for duplicate keys whose request body matches the original.
- Return
409 Conflictif the key is reused with a mismatched body. See Message Signatures — Idempotency Key Requirements for the full payload-matching contract.
| Status Code | Description |
|---|---|
200 OK |
The request was successful. |
201 Created |
The cart was successfully created. |
400 Bad Request |
The request was invalid or cannot be served. |
401 Unauthorized |
Authentication is required and has failed or has not been provided. |
403 Forbidden |
The request is authenticated but the user does not have the necessary permissions. |
409 Conflict |
The request could not be completed due to a conflict (e.g., idempotent key reuse). |
422 Unprocessable Entity |
The profile content is malformed (discovery failure). |
424 Failed Dependency |
The profile URL is valid but fetch failed (discovery failure). |
429 Too Many Requests |
Rate limit exceeded. |
500 Internal Server Error |
An unexpected condition was encountered on the server. |
503 Service Unavailable |
Temporary unavailability. |
See the Core Specification for the complete error code registry and transport binding examples.
- Protocol errors: Return appropriate HTTP status code (401, 403, 409, 429,
503) with JSON body containing
codeandcontent. - Business outcomes: Return HTTP 200 with UCP envelope and
messagesarray.
Business outcomes (including not found and validation errors) are returned with
HTTP 200 and the UCP envelope containing messages:
{
"ucp": {
"version": "{{ ucp_version }}",
"status": "error",
"capabilities": {
"dev.ucp.shopping.cart": [{"version": "{{ ucp_version }}"}]
}
},
"messages": [
{
"type": "error",
"code": "not_found",
"content": "Cart not found or has expired",
"severity": "unrecoverable"
}
],
"continue_url": "https://merchant.com/"
}Authentication is optional and depends on business requirements. When authentication is required, the REST transport MAY use:
- Open API: No authentication required for public operations.
- API Keys: Via
X-API-Keyheader. - OAuth 2.0: Via
Authorization: Bearer {token}header. Identifies the platform for agent-authenticated access, or both platform and user for user-authenticated access (see Identity Linking). - Mutual TLS: For high-security environments.
Businesses MAY require authentication for some operations while leaving others open (e.g., public cart without authentication).