Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions docs/specification/return.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<!--
Copyright 2026 UCP Authors

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
-->

# Return Extension

## Overview

The Return Extension allows businesses to communicate the conditions, methods, timelines, and costs associated with returning physical items directly to the platform and the buyer, mirroring real-world commerce requirements.

By exposing the return policy natively in the UCP schema, AI agents and platforms can intelligently answer user queries like *"Can I return this in-store?"* or *"How many days do I have to return this?"* without forcing the user to leave the platform to hunt for a policy on the merchant's website.

This extension adds a `return_policies` field to Checkout containing:

* `return_policies[]` — conditions governed by the merchant for specific items.
* `return_window_type` — the category of return window (finite, lifetime, final sale, etc.)
* `return_days` — the number of days in the window.
* `methods[]` — permitted physical methods (in-store, by-mail, etc.)
* `fee` — the cost structure for that specific method.

**Mental model:**

* `return_policies[0]` Standard Apparel
* `line_item_ids` 👕👖
* `return_window_type` = `finite_window` 🗓️ 30 Days
* `methods[0]` In-Store 🏬
* `fee` = `free` ✅
* `methods[1]` By Mail 📦
* `fee` = `fixed_fee` $5.00 💸
* `return_policies[1]` Final Sale
* `line_item_ids` ⌚
* `return_window_type` = `final_sale` 🚫
* `exchanges_allowed` = `false`

## Schema

Return policies apply to physical items in a checkout session. Items not governed by a specific policy (e.g., digital services) may be omitted or covered by a default policy.

### Properties

{{ extension_fields('return', 'return_policies') }}

### Entities

#### Return Policy

{{ schema_fields('types/return_policy', 'return') }}

#### Return Method

{{ schema_fields('types/return_method', 'return') }}

#### Return Fee

{{ schema_fields('types/return_fee', 'return') }}

## Rendering

Return policies are designed for proactive disclosures by the merchant. Platforms use these fields to provide transparency about the logistical requirements of a purchase before completion.

### Human-Readable Fields

| Location | Field | Required | Purpose |
| ---------------------- | -------------- | -------- | --------------------------------------------------- |
| `return_policy` | `return_days` | No | Quantitative window for the return. |
| `return_method.fee` | `display_text` | No | Context for the fee (e.g., "Restocking Fee"). |
| `return_method.fee` | `amount` | No | Price in minor units for fixed fees. |

### Business Responsibilities

**For `return_window_type`:**

* **MUST** accurately reflect the merchant's legal and commercial policy.
* **MUST** provide `return_days` if the type is `finite_window`.

**For `return_method.fee`:**

* **SHOULD** use `display_text` to explain the nature of the fee (e.g., "Prepaid Label", "Restocking Fee").
* **MUST** provide `amount` if the type is `fixed_fee`.

### Platform Responsibilities

Platforms **SHOULD** use return policies to answer buyer questions and provide assurance:

* Surface "Final Sale" warnings early in the checkout flow.
* Answer specific questions like "Is return shipping free?" by inspecting the `by_mail` method fee.
* Use `return_days` to calculate and display the specific return deadline based on the delivery date.

## Examples

### Mixed Cart

In this example, apparel items have a standard window, while a custom item is final sale.

```json
{
"return_policies": [
{
"id": "rp_apparel",
"line_item_ids": ["shirt", "pants"],
"return_window_type": "finite_window",
"return_days": 30,
"exchanges_allowed": true,
"methods": [
{
"type": "in_store",
"fee": {
"type": "free",
"display_text": "Free In-Store Return"
}
},
{
"type": "by_mail",
"fee": {
"type": "fixed_fee",
"amount": 500,
"display_text": "Return Shipping Fee"
}
}
]
},
{
"id": "rp_final_sale",
"line_item_ids": ["custom_engraved_watch"],
"return_window_type": "final_sale",
"exchanges_allowed": false
}
]
}
```
1 change: 1 addition & 0 deletions mkdocs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ nav:
- Buyer Consent Extension: specification/buyer-consent.md
- Discounts Extension: specification/discount.md
- Fulfillment Extension: specification/fulfillment.md
- Return Extension: specification/return.md
- Cart Capability:
- Overview: specification/cart.md
- HTTP/REST Binding: specification/cart-rest.md
Expand Down
60 changes: 60 additions & 0 deletions source/schemas/shopping/return.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://ucp.dev/schemas/shopping/return.json",
"name": "dev.ucp.shopping.return",
"title": "Return Extension",
"description": "Extends Checkout with return policy support.",
"$defs": {
"return_policy": {
"$ref": "types/return_policy.json"
},
"return_method": {
"$ref": "types/return_method.json"
},
"return_fee": {
"$ref": "types/return_fee.json"
},
"dev.ucp.shopping.checkout": {
"title": "Checkout with Return",
"description": "Checkout extended with return policies.",
"allOf": [
{
"$ref": "checkout.json"
},
{
"type": "object",
"properties": {
"return_policies": {
"type": "array",
"items": {
"$ref": "#/$defs/return_policy"
},
"description": "Return policies applicable to items in the checkout.",
"ucp_request": "omit"
}
}
}
]
},
"dev.ucp.shopping.return": {
"platform_schema": {
"title": "Return Capability (Platform)",
"description": "Platform-level return capability configuration",
"allOf": [
{
"$ref": "../capability.json#/$defs/platform_schema"
}
]
},
"business_schema": {
"title": "Return Capability (Business)",
"description": "Business-level return capability configuration",
"allOf": [
{
"$ref": "../capability.json#/$defs/business_schema"
}
]
}
}
}
}
23 changes: 23 additions & 0 deletions source/schemas/shopping/types/return_fee.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://ucp.dev/schemas/shopping/types/return_fee.json",
"title": "Return Fee",
"description": "The cost structure associated with a specific return method.",
"type": "object",
"required": ["type"],
"properties": {
"type": {
"type": "string",
"enum": ["free", "fixed_fee", "customer_responsibility"],
"description": "The cost structure for the return method."
},
"amount": {
"$ref": "amount.json",
"description": "Fixed return fee charged by the merchant, represented in minor currency units (e.g., cents). Required if type is fixed_fee."
},
"display_text": {
"type": "string",
"description": "Human-readable text to display against the fee to provide context to the buyer (e.g., 'Restocking Fee', 'Return Shipping Label')."
}
}
}
19 changes: 19 additions & 0 deletions source/schemas/shopping/types/return_method.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://ucp.dev/schemas/shopping/types/return_method.json",
"title": "Return Method",
"description": "The physical method through which the buyer can return the item.",
"type": "object",
"required": ["type", "fee"],
"properties": {
"type": {
"type": "string",
"enum": ["in_store", "by_mail", "kiosk"],
"description": "The physical method through which the buyer can return the item."
},
"fee": {
"$ref": "return_fee.json",
"description": "The cost structure associated with this specific return method."
}
}
}
37 changes: 37 additions & 0 deletions source/schemas/shopping/types/return_policy.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://ucp.dev/schemas/shopping/types/return_policy.json",
"title": "Return Policy",
"description": "Conditions, methods, timelines, and costs associated with returning physical items.",
"type": "object",
"required": ["id", "line_item_ids", "return_window_type"],
"properties": {
"id": {
"type": "string",
"description": "Unique identifier for the return policy."
},
"line_item_ids": {
"type": "array",
"items": { "type": "string" },
"description": "Line items governed by this return policy, allowing distinct policies per item."
},
"return_window_type": {
"type": "string",
"enum": ["lifetime", "no_returns", "final_sale", "finite_window"],
"description": "The type of return window."
},
"return_days": {
"type": "integer",
"description": "Number of days allowed for a return, typically starting from the date of delivery. Required if category is finite_window."
},
"exchanges_allowed": {
"type": "boolean",
"description": "Indicates whether the buyer can exchange the item."
},
"methods": {
"type": "array",
"items": { "$ref": "return_method.json" },
"description": "Permitted physical methods for returning the item, along with their associated fee structures."
}
}
}