Skip to content
DocsDashboard

Dates (date_range)

A calendar for choosing one date or a date range (stays, appointments, deadlines).

When to use it: The person picks a date, or a check-in and check-out range, on a calendar with limits and unavailable days.

When not to use it: Do not use it when you already have specific times or a few fixed options to offer (use time_slots), or for a single date the person can just type in chat.

Gather first:

  • Whether you need one date (mode: "single") or a stay from start to end ("range").
  • The earliest and latest dates you can work with, and any dates that are not possible.

Writing good content:

  • Set minDate and maxDate to the real window and list impossible days in disabledDates, so the person cannot pick a date you cannot use.
  • For stays, set minNights and maxNights when the place requires them. For any other period (a trip, time off, a deadline window) set stay: false, so the page does not count nights.
  • Use dayNotes for a very short note under a day, such as a nightly price, only when you have it for those days.

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
mode"single" | "range", required. "single" picks one date; "range" picks a start and an end date.
minDatestring. Earliest selectable date. Days before it are disabled. Defaults to no limit.
maxDatestring. Latest selectable date. Days after it are disabled. Defaults to no limit.
disabledDatesstring[]. Dates that cannot be chosen, e.g. days with no availability. A range cannot span a disabled date. Limits: at most 400 items.
minNightsinteger. Range mode only: fewest nights (endDate minus startDate). Defaults to 1. Limits: 1-365.
maxNightsinteger. Range mode only: most nights. Defaults to no limit. Limits: 1-365.
stayboolean. Range mode only. Omit or true for a stay (check-in to check-out): the page counts and shows nights. false for any other period (a trip, time off, a deadline window): no night count, and minNights/maxNights read as days between the dates.
dayNotesobject[]. Optional small note per date, usually a price, e.g. { "date": "2026-11-03", "note": "$129" }. Limits: at most 400 items.
dayNotes[].datestring, required. Calendar date as "YYYY-MM-DD", e.g. "2026-11-03". No time or time zone.
dayNotes[].notestring, required. Very short text under the day number, e.g. "$129". Max 8 characters. Limits: 1-8 characters.
defaultValueobject. Optional preselected answer. Use { date } in single mode or { startDate, endDate } in range mode.
defaultValue (variant 1).datestring, required. The chosen date, "YYYY-MM-DD".
defaultValue (variant 2).startDatestring, required. First day of the range (check-in), "YYYY-MM-DD".
defaultValue (variant 2).endDatestring, required. Last day of the range (check-out), "YYYY-MM-DD". Nights = endDate minus startDate.

Why these are required: It decides the result shape ({ date } or { startDate, endDate }).

When optional fields are left out: No limits; at least 1 night in range mode; a range is a stay and the page counts nights (stay: false drops the night count for other periods); nothing preselected.

Minimal example

Only the required fields:

{
  "version": 1,
  "title": "When should the piano tuner come?",
  "page": {
    "type": "date_range",
    "mode": "single"
  }
}

Full example

{
  "version": 1,
  "title": "Pick your dates at Harbor Light Inn",
  "description": "Nightly rates are shown under each day. Stays are 2 to 7 nights.",
  "branding": {
    "name": "Juniper Concierge",
    "accentColor": "#0050d8"
  },
  "page": {
    "type": "date_range",
    "mode": "range",
    "minDate": "2026-11-02",
    "maxDate": "2027-01-31",
    "minNights": 2,
    "maxNights": 7,
    "disabledDates": [
      "2026-11-12",
      "2026-11-13",
      "2026-11-27"
    ],
    "dayNotes": [
      {
        "date": "2026-11-03",
        "note": "$129"
      },
      {
        "date": "2026-11-04",
        "note": "$129"
      },
      {
        "date": "2026-11-05",
        "note": "$139"
      },
      {
        "date": "2026-11-06",
        "note": "$159"
      },
      {
        "date": "2026-11-07",
        "note": "$189"
      },
      {
        "date": "2026-11-08",
        "note": "$189"
      },
      {
        "date": "2026-11-09",
        "note": "$149"
      },
      {
        "date": "2026-11-10",
        "note": "$129"
      },
      {
        "date": "2026-11-11",
        "note": "$129"
      },
      {
        "date": "2026-11-12",
        "note": "$135"
      },
      {
        "date": "2026-11-13",
        "note": "$155"
      },
      {
        "date": "2026-11-14",
        "note": "$185"
      },
      {
        "date": "2026-11-15",
        "note": "$189"
      },
      {
        "date": "2026-11-16",
        "note": "$149"
      },
      {
        "date": "2026-11-17",
        "note": "$129"
      },
      {
        "date": "2026-11-18",
        "note": "$129"
      },
      {
        "date": "2026-11-19",
        "note": "$129"
      },
      {
        "date": "2026-11-20",
        "note": "$139"
      }
    ]
  }
}

Result

When the person submits, the result has these fields:

FieldDescription
(variant 1).datestring, required. The chosen date, "YYYY-MM-DD".
(variant 2).startDatestring, required. First day of the range (check-in), "YYYY-MM-DD".
(variant 2).endDatestring, required. Last day of the range (check-out), "YYYY-MM-DD". Nights = endDate minus startDate.

For the full example above, a result could be:

{
  "startDate": "2026-11-03",
  "endDate": "2026-11-06"
}

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 "date_range" (the same JSON as GET /v1/page-types/date_range), then create_page with this input (no version or branding; branding comes from your dashboard):

{
  "title": "Pick your dates at Harbor Light Inn",
  "description": "Nightly rates are shown under each day. Stays are 2 to 7 nights.",
  "page": {
    "type": "date_range",
    "mode": "range",
    "minDate": "2026-11-02",
    "maxDate": "2027-01-31",
    "minNights": 2,
    "maxNights": 7,
    "disabledDates": [
      "2026-11-12",
      "2026-11-13",
      "2026-11-27"
    ],
    "dayNotes": [
      {
        "date": "2026-11-03",
        "note": "$129"
      },
      {
        "date": "2026-11-04",
        "note": "$129"
      },
      {
        "date": "2026-11-05",
        "note": "$139"
      },
      {
        "date": "2026-11-06",
        "note": "$159"
      },
      {
        "date": "2026-11-07",
        "note": "$189"
      },
      {
        "date": "2026-11-08",
        "note": "$189"
      },
      {
        "date": "2026-11-09",
        "note": "$149"
      },
      {
        "date": "2026-11-10",
        "note": "$129"
      },
      {
        "date": "2026-11-11",
        "note": "$129"
      },
      {
        "date": "2026-11-12",
        "note": "$135"
      },
      {
        "date": "2026-11-13",
        "note": "$155"
      },
      {
        "date": "2026-11-14",
        "note": "$185"
      },
      {
        "date": "2026-11-15",
        "note": "$189"
      },
      {
        "date": "2026-11-16",
        "note": "$149"
      },
      {
        "date": "2026-11-17",
        "note": "$129"
      },
      {
        "date": "2026-11-18",
        "note": "$129"
      },
      {
        "date": "2026-11-19",
        "note": "$129"
      },
      {
        "date": "2026-11-20",
        "note": "$139"
      }
    ]
  }
}

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 your dates at Harbor Light Inn","description":"Nightly rates are shown under each day. Stays are 2 to 7 nights.","branding":{"name":"Juniper Concierge","accentColor":"#0050d8"},"page":{"type":"date_range","mode":"range","minDate":"2026-11-02","maxDate":"2027-01-31","minNights":2,"maxNights":7,"disabledDates":["2026-11-12","2026-11-13","2026-11-27"],"dayNotes":[{"date":"2026-11-03","note":"$129"},{"date":"2026-11-04","note":"$129"},{"date":"2026-11-05","note":"$139"},{"date":"2026-11-06","note":"$159"},{"date":"2026-11-07","note":"$189"},{"date":"2026-11-08","note":"$189"},{"date":"2026-11-09","note":"$149"},{"date":"2026-11-10","note":"$129"},{"date":"2026-11-11","note":"$129"},{"date":"2026-11-12","note":"$135"},{"date":"2026-11-13","note":"$155"},{"date":"2026-11-14","note":"$185"},{"date":"2026-11-15","note":"$189"},{"date":"2026-11-16","note":"$149"},{"date":"2026-11-17","note":"$129"},{"date":"2026-11-18","note":"$129"},{"date":"2026-11-19","note":"$129"},{"date":"2026-11-20","note":"$139"}]}}}'

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 mode:

✖ Invalid option: expected one of "single"|"range"
  → at page.mode

Misspelling a field name (unknown keys are rejected):

✖ Unrecognized key: "colour"
  → at page