Appointment Extension

Version: 0.0.1

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 Salon
    • selected_option_idopt_10am
    • options[0] ✅ 10:00 AM with Jane
    • options[1] 10:30 AM with Jane
  • appointment.slots[1] Massage (line_item_ids: ["li_2"])
    • location ✅ Uptown Spa
    • selected_option_idopt_2pm
    • options[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_ids into slots.
  • The business provides options[] for each slot.
  • The platform selects an option by setting selected_option_id for the slot (and may add notes).

Schema reference: https://viaschema.com/schemas/shopping/appointment.json

Properties

NameTypeRequiredDescription
appointmentAppointmentNoAppointment details.

Entities

Appointment

NameTypeRequiredDescription
slotsArray[Appointment Slot]NoAppointment slots for line items.

Appointment Slot

NameTypeRequiredDescription
idstringYesSlot identifier for referencing merchant-generated slots in updates.
line_item_idsArray[string]YesCheckout line item IDs included in this appointment slot.
locationRetail Location ResponseNoLocation for the appointment.
optionsArray[Appointment Option]NoAvailable appointment options for this slot.
selected_option_idstring | nullNoID of the selected appointment option for this slot.
notesstringNoOptional customer notes for the appointment.

Notes:

  • Appointment Slot allows additional properties (additionalProperties: true) for merchant-specific fields.
  • In UCP request semantics, the slot id is omitted on create and required on update.

Appointment Option

NameTypeRequiredDescription
idstringYesUnique appointment option identifier.
titlestringNoShort label for the time slot (e.g., "10:00 AM with Sarah").
start_timestring (date-time)YesAppointment start time.
end_timestring (date-time)NoAppointment end time.
duration_minutesintegerNoDuration of the appointment in minutes.
staffStaffNoStaff member assigned to this time slot.

Notes:

  • Appointment Option allows additional properties (additionalProperties: true) for merchant-specific fields.
  • In UCP request semantics, options[] are business-owned; platforms select by setting selected_option_id.

Staff

NameTypeRequiredDescription
idstringYesUnique staff member identifier.
namestringYesFull display name of the staff member.
first_namestringNoFirst name of the staff member.
last_namestringNoLast 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

LocationFieldRequiredPurpose
slots[].options[]titleNoPrimary label that distinguishes options (recommended).
slots[].options[]start_time / end_timeYes / NoMachine-readable schedule times for rendering date/time.
slots[].options[]duration_minutesNoSupports duration display.
slots[].locationnameNoLocation name for rendering.
slots[]notesNoBuyer-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 title that is sufficient for buyer decision making.
  • SHOULD provide options in a meaningful order (e.g., soonest first).

For slots[].location:

  • SHOULD populate location.name for display.
  • MAY omit location if the service is location-independent (e.g., remote).

For slots[].line_item_ids:

  • MUST reference checkout line_items[].id values (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 formatted start_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:

NameRequiredSchemaDescription
checkoutYeshttps://ucp.dev/schemas/shopping/checkout.jsonCurrent 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:

NameRequiredSchemaDescription
checkoutYeshttps://ucp.dev/schemas/shopping/checkout.jsonCurrent 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.

NameTypeRequiredDescription
configobjectNoPlatform 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.

NameTypeRequiredDescription
configobjectNoBusiness 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 optionally notes) 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:

  1. Extends com.viaschema.appointment.
  2. Adds well-defined properties (and enums where needed).
  3. 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_SANDBOXtrue/false to select sandbox vs production (defaults to true)

Tool surface (ADK / A2A typed responses):

ToolPurposeKey inputsOutput (typed key / object)
search_shopping_catalogSearch servicesquerya2a.service_results[]
list_locationsList bookable locationsquery?a2a.locations[]
list_staffList staff membersquery?a2a.staff[]
search_availabilityFind available appointment timesstart_date, end_date, location_id?, staff_id?, service_variation_id?a2a.availability_slots[]
add_to_checkoutAdd a service line item (optionally scheduled)service_variation_id, quantity?, location_id?, staff_id?, start_time?, notes?checkout
remove_from_checkoutRemove a line item (and its slot association)line_item_idcheckout
update_checkoutUpdate quantity and/or appointment detailsline_item_id, quantity?, location_id?, staff_id?, start_time?, notes?checkout
set_appointmentSet appointment details for multiple line itemsslots[]checkout
update_customer_detailsSet buyer details (email required)email, first_name?, last_name?, phone?checkout or requires_more_info
start_paymentValidate readiness to pay / book(uses current checkout)checkout or requires_more_info
complete_checkoutCollect payment and create bookings(uses stored payment & checkout)checkout (order confirmation)
get_bookingsList existing bookingsquery?a2a.bookings[]
cancel_bookingCancel an existing bookingbooking_idmessage