Skip to content
DocsDashboard

Time slots (time_slots)

Let the person pick one or several time slots across one or more days (tables, appointments, meetings). The page records the choice; it does not reserve the slot.

When to use it: The person picks one or more times from open slots grouped by day: a table, an appointment, a meeting. The page only records the choice: reserve or schedule it yourself afterwards, and do not tell the person it is confirmed until you have.

When not to use it: Do not use it to find any free time on the person's calendar (it shows only the slots you supply), or for an open-ended date (use date_range).

Gather first:

  • The real open slots from the venue, calendar or service, for the next few days.
  • Whether the person should pick one slot or several (multiple).

Writing good content:

  • Group slots by day, earliest first. Give each slot a start with the venue's UTC offset and set timeZone so the page shows local time.
  • Mark slots that just filled up with available: false rather than removing them, so the grid stays readable.
  • Use label for a short extra like "Patio", and price only when slots cost different amounts.
  • The answer is the chosen slot ids. Request the booking yourself afterwards.

Fields

Every page also has version (always 1), title, and optionally description, branding, cover (a header photo) and expiresAt; see Page fields. These are the fields of page (the page type and its data):

FieldDescription
timeZonestring. Optional IANA time zone the times are shown in, e.g. "America/Los_Angeles". It is displayed on the page. Include when known; omit otherwise and each time is shown at the UTC offset written in it.
daysobject[], required. Days with their slots, in display order (1-14 days). Limits: 1-14 items.
days[].datestring, required. The day these slots fall on, "YYYY-MM-DD", in timeZone (or in the slot start's own UTC offset when timeZone is omitted). Days are shown in the order given.
days[].slotsobject[], required. Slots on this day, earliest first (1-48). Limits: 1-48 items.
days[].slots[].idstring, required. Stable identifier you choose. It is returned in the result, so keep it meaningful to you. Limits: matches ^[A-Za-z0-9_-]{1,64}$.
days[].slots[].startISO 8601 timestamp, required. Start time as ISO 8601 with UTC offset, e.g. "2026-11-03T19:30:00-08:00".
days[].slots[].endISO 8601 timestamp. Optional end time as ISO 8601 with UTC offset, e.g. "2026-11-03T19:30:00-08:00".
days[].slots[].labelstring. Short extra text on the chip, e.g. "Bar seating" or "Dr. Rivera". Limits: 1-60 characters.
days[].slots[].priceobject. Optional price for this slot. Include only when slots cost different amounts.
days[].slots[].price.amountnumber, required. Amount in major units, e.g. 249.99 for $249.99. Limits: 0-10000000.
days[].slots[].price.currencystring, required. ISO 4217 currency code, uppercase, e.g. "USD", "EUR".
days[].slots[].availableboolean. false shows the slot as disabled (taken). Omit for an open slot. Keep taken slots so the person sees them.
multipleboolean. true lets the person pick several slots. Omit or false for exactly one.
minSelectionsinteger. Only when multiple is true: the fewest slots required. Defaults to 1. Limits: at least 1.
maxSelectionsinteger. Only when multiple is true: the most slots allowed. Defaults to all available. Limits: at least 1.

Why these are required: A slot needs an id and a time, grouped by day.

When optional fields are left out: Times are shown at each timestamp's UTC offset and the "Times shown in" line is hidden; single choice; a slot is open unless available is false.

Minimal example

Only the required fields:

{
  "version": 1,
  "title": "Pick a time for your bike tune-up",
  "page": {
    "type": "time_slots",
    "days": [
      {
        "date": "2026-11-10",
        "slots": [
          {
            "id": "t0900",
            "start": "2026-11-10T09:00:00-05:00"
          },
          {
            "id": "t1100",
            "start": "2026-11-10T11:00:00-05:00"
          },
          {
            "id": "t1400",
            "start": "2026-11-10T14:00:00-05:00"
          }
        ]
      },
      {
        "date": "2026-11-11",
        "slots": [
          {
            "id": "w1000",
            "start": "2026-11-11T10:00:00-05:00"
          },
          {
            "id": "w1530",
            "start": "2026-11-11T15:30:00-05:00"
          }
        ]
      }
    ]
  }
}

Full example

{
  "version": 1,
  "title": "Pick a time at Ember & Stone",
  "description": "Table for four. Pick the time that suits you.",
  "branding": {
    "name": "Juniper Concierge",
    "accentColor": "#0050d8"
  },
  "cover": {
    "url": "https://images.example.test/ember.jpg",
    "alt": "Wood-fired pizza coming out of the oven at Ember & Stone"
  },
  "page": {
    "type": "time_slots",
    "timeZone": "America/Los_Angeles",
    "multiple": false,
    "days": [
      {
        "date": "2026-11-06",
        "slots": [
          {
            "id": "f1730",
            "start": "2026-11-06T17:30:00-08:00",
            "available": true
          },
          {
            "id": "f1800",
            "start": "2026-11-06T18:00:00-08:00",
            "available": false
          },
          {
            "id": "f1830",
            "start": "2026-11-06T18:30:00-08:00",
            "available": true
          },
          {
            "id": "f1900",
            "start": "2026-11-06T19:00:00-08:00",
            "available": true
          },
          {
            "id": "f1930",
            "start": "2026-11-06T19:30:00-08:00",
            "available": false
          },
          {
            "id": "f2000",
            "start": "2026-11-06T20:00:00-08:00",
            "available": true
          }
        ]
      },
      {
        "date": "2026-11-07",
        "slots": [
          {
            "id": "s1730",
            "start": "2026-11-07T17:30:00-08:00",
            "available": true
          },
          {
            "id": "s1800",
            "start": "2026-11-07T18:00:00-08:00",
            "available": true
          },
          {
            "id": "s1900",
            "start": "2026-11-07T19:00:00-08:00",
            "available": false
          }
        ]
      }
    ]
  }
}

Result

When the person submits, the result has these fields:

FieldDescription
selectedSlotIdsstring[], required. ids of the chosen slots, in display order. Limits: 1-100 items.

For the full example above, a result could be:

{
  "selectedSlotIds": [
    "f1900"
  ]
}

Send it

eve, AI SDK and MCP

With @pagesystems/eve, @pagesystems/ai-sdk or the MCP server, the model calls get_page_type_schema with "time_slots" (the same JSON as GET /v1/page-types/time_slots), then create_page with this input (no version or branding; branding comes from your dashboard):

{
  "title": "Pick a time at Ember & Stone",
  "description": "Table for four. Pick the time that suits you.",
  "cover": {
    "url": "https://images.example.test/ember.jpg",
    "alt": "Wood-fired pizza coming out of the oven at Ember & Stone"
  },
  "page": {
    "type": "time_slots",
    "timeZone": "America/Los_Angeles",
    "multiple": false,
    "days": [
      {
        "date": "2026-11-06",
        "slots": [
          {
            "id": "f1730",
            "start": "2026-11-06T17:30:00-08:00",
            "available": true
          },
          {
            "id": "f1800",
            "start": "2026-11-06T18:00:00-08:00",
            "available": false
          },
          {
            "id": "f1830",
            "start": "2026-11-06T18:30:00-08:00",
            "available": true
          },
          {
            "id": "f1900",
            "start": "2026-11-06T19:00:00-08:00",
            "available": true
          },
          {
            "id": "f1930",
            "start": "2026-11-06T19:30:00-08:00",
            "available": false
          },
          {
            "id": "f2000",
            "start": "2026-11-06T20:00:00-08:00",
            "available": true
          }
        ]
      },
      {
        "date": "2026-11-07",
        "slots": [
          {
            "id": "s1730",
            "start": "2026-11-07T17:30:00-08:00",
            "available": true
          },
          {
            "id": "s1800",
            "start": "2026-11-07T18:00:00-08:00",
            "available": true
          },
          {
            "id": "s1900",
            "start": "2026-11-07T19:00:00-08:00",
            "available": false
          }
        ]
      }
    ]
  }
}

REST

curl https://pagesystems.ai/v1/pages \
  -H "Authorization: Bearer $PAGE_SYSTEMS_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"spec":{"version":1,"title":"Pick a time at Ember & Stone","description":"Table for four. Pick the time that suits you.","branding":{"name":"Juniper Concierge","accentColor":"#0050d8"},"cover":{"url":"https://images.example.test/ember.jpg","alt":"Wood-fired pizza coming out of the oven at Ember & Stone"},"page":{"type":"time_slots","timeZone":"America/Los_Angeles","multiple":false,"days":[{"date":"2026-11-06","slots":[{"id":"f1730","start":"2026-11-06T17:30:00-08:00","available":true},{"id":"f1800","start":"2026-11-06T18:00:00-08:00","available":false},{"id":"f1830","start":"2026-11-06T18:30:00-08:00","available":true},{"id":"f1900","start":"2026-11-06T19:00:00-08:00","available":true},{"id":"f1930","start":"2026-11-06T19:30:00-08:00","available":false},{"id":"f2000","start":"2026-11-06T20:00:00-08:00","available":true}]},{"date":"2026-11-07","slots":[{"id":"s1730","start":"2026-11-07T17:30:00-08:00","available":true},{"id":"s1800","start":"2026-11-07T18:00:00-08:00","available":true},{"id":"s1900","start":"2026-11-07T19:00:00-08:00","available":false}]}]}}}'

Validation errors

A spec that does not validate is refused with 400 invalid_spec. The message names each problem and its path, so a model can fix the spec and try again. For example:

Leaving out the required field days:

✖ Invalid input: expected array, received undefined
  → at page.days

Misspelling a field name (unknown keys are rejected):

✖ Unrecognized key: "colour"
  → at page