Appointment Extension
Overview
The appointment extension enables businesses to advertise support for time-based service booking (appointments) during checkout.
This extension adds an appointment field to Checkout containing one or more appointment slots. Each slot groups one or more checkout line_items that must be scheduled together, and provides selectable options (time slots and optionally staff).
Capability: com.viaschema.appointment
Extends: dev.ucp.shopping.checkout
Mental model:
appointment.slots[0]Haircut (line_item_ids:["li_1"])location✅ Downtown Salonselected_option_id✅opt_10amoptions[0]✅ 10:00 AM with Janeoptions[1]10:30 AM with Jane
appointment.slots[1]Massage (line_item_ids:["li_2"])location✅ Uptown Spaselected_option_id✅opt_2pmoptions[0]✅ 2:00 PM (any available staff)options[1]2:30 PM (any available staff)
Appointment applies only to items that require booking. Items that do not require an appointment (e.g., physical goods, digital goods) do not need to be assigned to a slot.
Schema
Appointment slots are designed to be business-generated and business-owned:
- The business decides how to group
line_item_idsinto slots. - The business provides
options[]for each slot. - The platform selects an option by setting
selected_option_idfor the slot (and may addnotes).
Schema reference:
https://viaschema.com/schemas/shopping/appointment.json
Properties
| Name | Type | Required | Description |
|---|---|---|---|
appointment | Appointment | No | Appointment details. |
Entities
Appointment
| Name | Type | Required | Description |
|---|---|---|---|
slots | Array[Appointment Slot] | No | Appointment slots for line items. |
Appointment Slot
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Slot identifier for referencing merchant-generated slots in updates. |
line_item_ids | Array[string] | Yes | Checkout line item IDs included in this appointment slot. |
location | Retail Location Response | No | Location for the appointment. |
options | Array[Appointment Option] | No | Available appointment options for this slot. |
selected_option_id | string | null | No | ID of the selected appointment option for this slot. |
notes | string | No | Optional customer notes for the appointment. |
Notes:
Appointment Slotallows additional properties (additionalProperties: true) for merchant-specific fields.- In UCP request semantics, the slot
idis omitted on create and required on update.
Appointment Option
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique appointment option identifier. |
title | string | No | Short label for the time slot (e.g., "10:00 AM with Sarah"). |
start_time | string (date-time) | Yes | Appointment start time. |
end_time | string (date-time) | No | Appointment end time. |
duration_minutes | integer | No | Duration of the appointment in minutes. |
staff | Staff | No | Staff member assigned to this time slot. |
Notes:
Appointment Optionallows additional properties (additionalProperties: true) for merchant-specific fields.- In UCP request semantics,
options[]are business-owned; platforms select by settingselected_option_id.
Staff
| Name | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Unique staff member identifier. |
name | string | Yes | Full display name of the staff member. |
first_name | string | No | First name of the staff member. |
last_name | string | No | Last name of the staff member. |
Retail Location Response
Appointment slots reference UCP's standard retail location type:
https://ucp.dev/schemas/shopping/types/retail_location.json
Example
{
"appointment": {
"slots": [
{
"id": "slot_1",
"line_item_ids": [
"li_1"
],
"location": {
"id": "loc_123",
"name": "Downtown Salon"
},
"options": [
{
"id": "opt_10am",
"title": "10:00 AM with Jane",
"start_time": "2026-02-12T18:00:00Z",
"end_time": "2026-02-12T18:30:00Z",
"duration_minutes": 30,
"staff": {
"id": "staff_123",
"name": "Jane Doe"
}
},
{
"id": "opt_10_30am",
"title": "10:30 AM with Jane",
"start_time": "2026-02-12T18:30:00Z",
"end_time": "2026-02-12T19:00:00Z",
"duration_minutes": 30,
"staff": {
"id": "staff_123",
"name": "Jane Doe"
}
}
],
"selected_option_id": "opt_10am",
"notes": "Please focus on the sides."
}
]
}
}
Rendering
Appointment options are designed for generic rendering. Platforms do not need deep business-specific logic to present appointment choices. The business provides precomputed, human-readable fields (notably options[].title and timestamps) that platforms render directly.
Human-Readable Fields
| Location | Field | Required | Purpose |
|---|---|---|---|
slots[].options[] | title | No | Primary label that distinguishes options (recommended). |
slots[].options[] | start_time / end_time | Yes / No | Machine-readable schedule times for rendering date/time. |
slots[].options[] | duration_minutes | No | Supports duration display. |
slots[].location | name | No | Location name for rendering. |
slots[] | notes | No | Buyer-entered notes, shown back to the buyer. |
Business Responsibilities
For slots[].options[]:
- MUST provide stable option
ids for the lifetime of the slot update cycle. - SHOULD provide
titlethat is sufficient for buyer decision making. - SHOULD provide options in a meaningful order (e.g., soonest first).
For slots[].location:
- SHOULD populate
location.namefor display. - MAY omit location if the service is location-independent (e.g., remote).
For slots[].line_item_ids:
- MUST reference checkout
line_items[].idvalues (not catalog IDs).
For completion readiness:
- If one or more services require appointment selection, businesses SHOULD treat checkout as incomplete until each relevant slot has a
selected_option_id.
Platform Responsibilities
Platforms SHOULD treat appointment as a generic, renderable structure:
- Render each slot with its
location(if present) and the selected option’s time. - Render available options using
title(if present) plus formattedstart_time. - When a buyer selects an option, update the checkout by setting
slots[].selected_option_id.
Platforms MAY provide enhanced UX:
- Calendar pickers, time grids, staff filters
- Location selection maps
- Timezone-aware rendering
If the platform cannot fully support appointment selection, the platform SHOULD use continue_url to hand off to the business’s checkout UI.
Available Methods
This extension defines embedded methods that help coordinate appointment selection between the business and the platform (especially for Embedded Checkout experiences).
ec.appointment.change
Summary: Appointment details changed
Description: Merchant notifies host that checkout.appointment has changed (e.g., slot selected, time updated).
Params:
| Name | Required | Schema | Description |
|---|---|---|---|
checkout | Yes | https://ucp.dev/schemas/shopping/checkout.json | Current checkout state with updated appointment. |
ec.appointment.slot_selection_request
Summary: Request appointment slot selection Description: Merchant requests host to present appointment slot selection UI.
Params:
| Name | Required | Schema | Description |
|---|---|---|---|
checkout | Yes | https://ucp.dev/schemas/shopping/checkout.json | Current checkout state with appointment context. |
Result: slotSelectionResult
The host returns a partial checkout update that includes the updated appointment selection:
{
"checkout": {
"appointment": {
"slots": [
{
"id": "slot_1",
"selected_option_id": "opt_10_30am",
"notes": "Please focus on the sides."
}
]
}
}
}
Configuration
Businesses and platforms may declare appointment constraints in their profiles. The appointment extension currently leaves config as an open object to support experimentation and ecosystem-specific negotiation.
Platform Profile
Platforms may advertise appointment-related rendering capabilities via the capability’s config object.
| Name | Type | Required | Description |
|---|---|---|---|
config | object | No | Platform appointment configuration (extension-defined; open schema). |
Example:
{ "name": "com.viaschema.appointment", "version": "2026-01-11" }
Business Profile
Businesses may advertise appointment constraints and supported behaviors via the capability’s config object.
| Name | Type | Required | Description |
|---|---|---|---|
config | object | No | Business appointment configuration (extension-defined; open schema). |
Example:
{
"capabilities": [{
"name": "com.viaschema.appointment",
"version": "2026-01-11",
"config": {}
}]
}
Business Response Behavior
- Businesses SHOULD return
appointment.slots[]for services that require scheduling. - Businesses SHOULD keep
options[]current with availability and business rules (location hours, staff schedules, service duration). - Platforms SHOULD update
selected_option_id(and optionallynotes) rather than attempting to create options.
Adding New Methods
This extension uses additionalProperties: true on core appointment entities to allow merchant-specific fields without breaking platforms.
If you want to standardize new behaviors (e.g., remote appointments, deposits, cancellation policies), create a new extension that:
- Extends
com.viaschema.appointment. - Adds well-defined properties (and enums where needed).
- Documents rendering and negotiation requirements for those properties.
Examples
Basic
Config: None required (default behavior)
Single service with a single appointment slot and multiple options.
{
"appointment": {
"slots": [
{
"id": "slot_1",
"line_item_ids": [
"li_1"
],
"location": {
"id": "loc_123",
"name": "Downtown Salon"
},
"options": [
{
"id": "opt_1",
"title": "10:00 AM",
"start_time": "2026-02-12T18:00:00Z"
},
{
"id": "opt_2",
"title": "10:30 AM",
"start_time": "2026-02-12T18:30:00Z"
}
],
"selected_option_id": "opt_1"
}
]
}
}
Split Slots
Two services require separate scheduling decisions. The business returns two slots (one per line item).
{
"appointment": {
"slots": [
{
"id": "slot_haircut",
"line_item_ids": [
"li_haircut"
],
"location": {
"id": "loc_123",
"name": "Downtown Salon"
},
"options": [
{
"id": "opt_h_10",
"title": "10:00 AM",
"start_time": "2026-02-12T18:00:00Z"
},
{
"id": "opt_h_11",
"title": "11:00 AM",
"start_time": "2026-02-12T19:00:00Z"
}
],
"selected_option_id": "opt_h_10"
},
{
"id": "slot_massage",
"line_item_ids": [
"li_massage"
],
"location": {
"id": "loc_456",
"name": "Uptown Spa"
},
"options": [
{
"id": "opt_m_2",
"title": "2:00 PM",
"start_time": "2026-02-12T22:00:00Z"
},
{
"id": "opt_m_3",
"title": "3:00 PM",
"start_time": "2026-02-12T23:00:00Z"
}
],
"selected_option_id": "opt_m_2"
}
]
}
}
Grouped Line Items
Multiple services are scheduled together (e.g., a "Cut + Beard" bundle). The business groups multiple line_item_ids into a single slot.
{
"appointment": {
"slots": [
{
"id": "slot_bundle",
"line_item_ids": [
"li_cut",
"li_beard"
],
"location": {
"id": "loc_123",
"name": "Downtown Salon"
},
"options": [
{
"id": "opt_bundle_10",
"title": "10:00 AM (60 min)",
"start_time": "2026-02-12T18:00:00Z",
"duration_minutes": 60
},
{
"id": "opt_bundle_11",
"title": "11:00 AM (60 min)",
"start_time": "2026-02-12T19:00:00Z",
"duration_minutes": 60
}
],
"selected_option_id": "opt_bundle_11",
"notes": "Prefer a quiet room if possible."
}
]
}
}
Reference Implementation Notes (Square Bookings)
This repository includes a reference implementation that backs appointment scheduling with Square Bookings:
- Service catalog is sourced from Square catalog items of type
APPOINTMENTS_SERVICE. - Availability is sourced from Square Bookings availability search.
- Bookings are created/cancelled via Square Bookings API.
Runtime configuration (environment variables):
SQUARE_ACCESS_TOKEN— Square access token (required to enable Square features)SQUARE_SANDBOX—true/falseto select sandbox vs production (defaults totrue)
Tool surface (ADK / A2A typed responses):
| Tool | Purpose | Key inputs | Output (typed key / object) |
|---|---|---|---|
search_shopping_catalog | Search services | query | a2a.service_results[] |
list_locations | List bookable locations | query? | a2a.locations[] |
list_staff | List staff members | query? | a2a.staff[] |
search_availability | Find available appointment times | start_date, end_date, location_id?, staff_id?, service_variation_id? | a2a.availability_slots[] |
add_to_checkout | Add a service line item (optionally scheduled) | service_variation_id, quantity?, location_id?, staff_id?, start_time?, notes? | checkout |
remove_from_checkout | Remove a line item (and its slot association) | line_item_id | checkout |
update_checkout | Update quantity and/or appointment details | line_item_id, quantity?, location_id?, staff_id?, start_time?, notes? | checkout |
set_appointment | Set appointment details for multiple line items | slots[] | checkout |
update_customer_details | Set buyer details (email required) | email, first_name?, last_name?, phone? | checkout or requires_more_info |
start_payment | Validate readiness to pay / book | (uses current checkout) | checkout or requires_more_info |
complete_checkout | Collect payment and create bookings | (uses stored payment & checkout) | checkout (order confirmation) |
get_bookings | List existing bookings | query? | a2a.bookings[] |
cancel_booking | Cancel an existing booking | booking_id | message |