Skip to content
Draft
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
65 changes: 26 additions & 39 deletions docs/specification/payment-terms.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,6 @@ terms and term-aware payment instruments.

{{ schema_fields('types/payment_schedule', 'payment_terms') }}

#### Schedule

{{ schema_fields('types/schedule', 'payment_terms') }}

#### Schedule Type

{{ schema_fields('types/schedule_type', 'payment_terms') }}
Expand All @@ -86,25 +82,23 @@ Payment schedules use `type` as an open string vocabulary. Well-known values are
| Type | Meaning |
| :--- | :------ |
| `immediate` | Payment is due when checkout is completed. |
| `deferred` | Payment is due after checkout completion, according to `due_at`. |
| `deferred` | Payment is due after checkout completion, as stated in `description`. |

Businesses MAY use additional values. Platforms MUST tolerate unknown schedule
types and either apply business-specific support or surface clear validation
messages when a selected payment instrument cannot satisfy them.

An `immediate` schedule **MUST** omit `due_at`; a `deferred` schedule **MUST**
include a non-empty `due_at`. The shared Schedule fields are:

* `anchor_date` — RFC 3339 reference point. If omitted, the anchor is the
instant successful checkout completion creates the order.
* `offset` — ISO 8601 duration from the anchor to the first occurrence.
* `interval` — ISO 8601 duration between recurring occurrences.
* `occurrences` — finite number of occurrences; **MUST** be present when
`interval` is present.
Every schedule has a buyer-facing `description` that **MUST** completely state
when and how its payment or payments are due. The `type` field provides only a
broad timing class; platforms do not infer dates or processor instructions from
it.

Each payment schedule has `totals[]`. For a recurring schedule, those totals
apply to each occurrence. Expanding every occurrence, the sum of schedule
`total` entries **MUST** equal the checkout `total` exactly once.
Each schedule's `totals[]` is the aggregate amount of every payment represented
by that schedule. A schedule may describe several occurrences in text, but its
`total` covers the complete series. If individual occurrences need different
instrument assignments, the business represents them as separate schedules.
The sum of schedule `total` entries **MUST** equal the checkout `total` exactly
once.

Schedules settle only the current checkout; they do not create future purchases,
orders, renewals, or fulfillment obligations. They disclose payment timing but
Expand Down Expand Up @@ -156,7 +150,7 @@ When the [Split Payments](split-payments.md) extension is also active,
instruments may include an `amount` field to specify a fixed contribution when
multiple instruments share a schedule. A fixed contribution **MUST** resolve to
exactly one schedule. Contributions to each schedule **MUST** equal that
schedule's expanded total, and every schedule **MUST** be covered by at least
schedule's aggregate total, and every schedule **MUST** be covered by at least
one eligible instrument.

## Discovery
Expand Down Expand Up @@ -226,6 +220,7 @@ When this extension is active, a completed Order **MUST** include exactly one
{
"id": "sched_first_night",
"type": "immediate",
"description": "Due when checkout is completed.",
"totals": [
{ "type": "subtotal", "amount": 30000 },
{ "type": "total", "amount": 30000 }
Expand All @@ -234,9 +229,7 @@ When this extension is active, a completed Order **MUST** include exactly one
{
"id": "sched_check_in_balance",
"type": "deferred",
"due_at": {
"anchor_date": "2026-09-01T15:00:00-07:00"
},
"description": "Due at check-in on September 1, 2026 at 3:00 PM PDT.",
"totals": [
{ "type": "subtotal", "amount": 90000 },
{ "type": "total", "amount": 90000 }
Expand Down Expand Up @@ -334,6 +327,7 @@ amounts.
{
"id": "sched_installment_1",
"type": "immediate",
"description": "One payment of $25 due when checkout is completed.",
"totals": [
{ "type": "subtotal", "amount": 2500 },
{ "type": "total", "amount": 2500 }
Expand All @@ -342,22 +336,18 @@ amounts.
{
"id": "sched_installments_2_to_4",
"type": "deferred",
"due_at": {
"offset": "P2W",
"interval": "P2W",
"occurrences": 3
},
"description": "Three payments of $25 due two, four, and six weeks after checkout.",
"totals": [
{ "type": "subtotal", "amount": 2500 },
{ "type": "total", "amount": 2500 }
{ "type": "subtotal", "amount": 7500 },
{ "type": "total", "amount": 7500 }
]
}
]
}
```

The deferred schedule has three occurrences. Its totals apply to each
occurrence, so the term expands to four payments of $25 each.
The deferred schedule describes three occurrences, while its totals represent
the aggregate $75 obligation assigned to that schedule.

### Order with accepted payment terms

Expand Down Expand Up @@ -435,6 +425,7 @@ The Order carries the complete accepted term from the originating Checkout.
{
"id": "sched_installment_1",
"type": "immediate",
"description": "One payment of $25 due when checkout is completed.",
"totals": [
{ "type": "subtotal", "amount": 2500 },
{ "type": "total", "amount": 2500 }
Expand All @@ -443,14 +434,10 @@ The Order carries the complete accepted term from the originating Checkout.
{
"id": "sched_installments_2_to_4",
"type": "deferred",
"due_at": {
"offset": "P2W",
"interval": "P2W",
"occurrences": 3
},
"description": "Three payments of $25 due two, four, and six weeks after checkout.",
"totals": [
{ "type": "subtotal", "amount": 2500 },
{ "type": "total", "amount": 2500 }
{ "type": "subtotal", "amount": 7500 },
{ "type": "total", "amount": 7500 }
]
}
]
Expand All @@ -465,7 +452,7 @@ The Order carries the complete accepted term from the originating Checkout.
Platforms SHOULD:

* Present available payment terms in a clear, buyer-understandable format.
* Show amounts and due dates for each schedule, including future payments.
* Show every schedule's aggregate amount and complete timing description.
* Validate term and schedule references plus instrument constraints before submitting payment.
* Tolerate unknown schedule types and surface clear recovery guidance when a
selected instrument cannot satisfy them.
Expand All @@ -475,7 +462,7 @@ Platforms SHOULD:
Businesses MUST:

* Provide at least one checkout-wide payment term when the extension is active.
* Ensure expanded schedule totals cover the checkout total exactly once.
* Ensure aggregate schedule totals cover the checkout total exactly once.
* Validate that all instrument assignments select the same term and completely
fund its schedules.
* Include that complete accepted term on the resulting Order.
Expand Down
14 changes: 7 additions & 7 deletions source/schemas/shopping/types/payment_schedule.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,25 @@
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://ucp.dev/schemas/shopping/types/payment_schedule.json",
"title": "Payment Schedule",
"description": "Defines when payment is due for a payment term. A schedule can represent a single payment or a recurring series of payments.",
"description": "A named payment obligation within a payment term. Timing is disclosed in buyer-facing text while totals provide a structured allocation amount.",
"type": "object",
"required": ["id", "type", "totals"],
"required": ["id", "type", "description", "totals"],
"properties": {
"id": {
"type": "string",
"description": "Unique identifier for this payment schedule."
},
"type": {
"$ref": "schedule_type.json",
"description": "Payment timing type. 'immediate' = captured immediately at order creation. 'deferred' = captured later per due_at schedule."
"description": "Broad payment timing class. Well-known values: `immediate` and `deferred`."
},
"due_at": {
"$ref": "schedule.json",
"description": "When the payment is due. Protocol semantics require this for deferred schedules and omit it for immediate schedules."
"description": {
"type": "string",
"description": "Complete buyer-facing explanation of when and how the payment is due."
},
"totals": {
"$ref": "totals.json",
"description": "Complete pricing breakdown for this obligation. The entry with `type: total` is the amount due in the checkout or order currency."
"description": "Aggregate pricing breakdown for every payment represented by this schedule. The entry with `type: total` is the complete amount allocated to the schedule in the checkout or order currency."
}
}
}
36 changes: 0 additions & 36 deletions source/schemas/shopping/types/schedule.json

This file was deleted.

Loading