{"product":"Cachet Calendar","suite":"Cachet","version":"2.27.0","updated":"2026-10-10","shipped":{"bookingPages":{"path":"/b/<handle>","anonymousInvitee":true},"calendarProvider":"google","calendarProvidersByOperation":{"display":["google","microsoft-365","outlook-com","icloud-caldav","fastmail-caldav"],"createAndEdit":["google"],"availabilityCheck":["google","microsoft-365","outlook-com"],"bookingDestination":["google"]},"googleScopes":["calendar.events","calendar.freebusy","calendar.calendarlist.readonly"],"freebusy":"live-poll-at-booking-time","doubleBookingGuard":true,"meetLink":true,"bothCalendarsUpdated":true,"dualTimezoneDisplay":true,"rescheduleCancelLink":true,"meetingTypes":true,"weeklyAvailability":true,"hostMeetingsList":true,"customInviteeQuestions":true,"calendarClient":{"path":"/calendar","web":true,"views":["agenda","day","week","month","quarter","year"],"multiCalendar":true,"perCalendarVisibility":"manual, saved, free tier","eventCreate":true,"eventEdit":true,"dragMoveAndResize":true,"eventDelete":true,"recurrence":{"standard":"RFC 5545 RRULE","library":"rrule.js","freqs":["DAILY","WEEKLY","BIWEEKLY","MONTHLY","YEARLY"],"dstCorrect":true,"plainEnglishPreview":true},"sync":{"method":"google-incremental-sync-token","webhookDependent":false,"autoResyncOnTokenExpiry":true,"autoWindowRebaseline":true,"syncStateShownToUser":true},"naturalLanguage":{"engine":"llm","provider":"cloudflare-workers-ai","refusesToGuessVagueTimes":true,"deterministicFallbackLabeled":true},"gridLibrary":"fullcalendar 6.1.19 (MIT), pinned with subresource integrity","standingInstructions":{"plainEnglish":true,"kinds":["protect-window","no-before","no-after","max-duration"],"enforcedOnBookingAvailability":true,"enforcedAtBookingConfirm":true,"sendsNoMessages":true,"reviewsExistingEvents":true,"autoDeclines":false}}},"coordination":{"path":"/c/<handle>","what":"group scheduling negotiation: N people converge on one contiguous block inside a coordinator-set window","inviteOnly":"every member holds a personal capability link; anonymous visitors see a gate with the title only","identityNote":"unlike the free poll cluster (display-name plus optional password, no email), membership is bound to an email","privacyModel":"aggregate counts only; no member ever sees another member's busy intervals or events","availabilitySources":["hand-painted grid","google freebusy (server-side merge)","any travel iCal feed: Trip Underway export, TripIt (all-day travel events block the whole day window)"],"candidateRanking":"live, full-block freedom; ties surfaced, never auto-resolved; quorum-aware","perBlockThreads":true,"responsesReEditable":"until decided","decideBooks":"one Google event, every member an attendee, Meet link, sendUpdates=all; without a coordinator Google grant the decision stands and members are emailed that the coordinator will send the invite","createWizard":"/coordinate (signed-in coordinators)"},"verifiedCompetitiveFacts":[{"claim":"Fantastical has no browser-based calendar client at any tier","source":"flexibits.com","checked":"2026-07-26"},{"claim":"Flexibits' Fantastical MCP connector is Mac-only, running against the local app database","source":"Flexibits blog","checked":"2026-07-26"}],"claims":[{"id":"booking-pages","text":"Public booking pages live at /b/<handle>, and an invitee books with no account.","test":"test/frontier/a14-journey.accept.mjs"},{"id":"calendars-shown-google-microsoft","text":"Google Calendar, Microsoft 365, and Outlook.com calendars appear together in the calendar client.","test":"test/calproviders.test.mjs"},{"id":"calendars-shown-caldav","text":"iCloud and Fastmail calendars connect over CalDAV and appear alongside them in the calendar client.","test":"test/calproviders.test.mjs"},{"id":"freebusy-live","text":"Availability is checked against Google Calendar free/busy, read live at booking time.","test":"test/frontier/a4-unavailable.accept.mjs"},{"id":"outlook-blocks-booking","text":"Events on a connected Microsoft 365 or Outlook.com calendar also block booking times, including calendars hidden from view.","test":"test/calproviders.test.mjs"},{"id":"double-booking-guard","text":"A booking is re-checked against the live calendar when it is confirmed, so a confirmed slot is open on the calendar at that moment.","test":"test/frontier/a1-scheduling.accept.mjs"},{"id":"booking-event-google","text":"Each booking creates a real event on the host's Google Calendar, with a Google Meet link on Meet meeting types.","test":"test/frontier/b3-location.accept.mjs"},{"id":"dual-timezone","text":"Every booking time is shown in both the host's time zone and the invitee's time zone.","test":"test/frontier/a10-copy.accept.mjs"},{"id":"reschedule-cancel-link","text":"Every booking carries a private reschedule and cancel link that needs no login.","test":"test/frontier/a14-journey.accept.mjs"},{"id":"meeting-types","text":"Each host configures meeting types with a name, length, and buffer.","test":"test/frontier/a1-scheduling.accept.mjs"},{"id":"weekly-availability","text":"Each host sets weekly availability.","test":"test/frontier/b1-windows.accept.mjs"},{"id":"host-meetings-list","text":"The host dashboard lists every booking, upcoming soonest first and past most recent first, with guest name, meeting type, and time in the host's zone.","test":"test/dashboard.test.mjs"},{"id":"canceled-stays-listed","text":"A canceled booking stays in the host's list with a Canceled label.","test":"test/dashboard.test.mjs"},{"id":"invitee-questions","text":"Custom invitee questions can be added to each meeting type, each required or optional.","test":"test/questions.test.mjs"},{"id":"required-answer-gate","text":"A missing required answer is rejected before any calendar event is created.","test":"test/questions.test.mjs"},{"id":"window-days","text":"Each meeting type sets how many days ahead it can be booked.","test":"test/frontier/a1-scheduling.accept.mjs"},{"id":"minimum-notice","text":"Each meeting type sets the minimum notice before a booking.","test":"test/frontier/a1-scheduling.accept.mjs"},{"id":"start-step","text":"Start times follow a step you choose, such as every 15, 20, 30, or 60 minutes.","test":"test/frontier/a1-scheduling.accept.mjs"},{"id":"buffers-before-after","text":"Each meeting type sets a buffer before and a buffer after, separately.","test":"test/frontier/a1-scheduling.accept.mjs"},{"id":"several-hours-per-day","text":"Each weekday can hold up to four separate sets of hours.","test":"test/frontier/b1-windows.accept.mjs"},{"id":"date-specific-hours","text":"A date-specific entry replaces that weekday's hours for one date, opening or closing it.","test":"test/frontier/b1-windows.accept.mjs"},{"id":"limit-per-day","text":"Each meeting type can limit bookings per day.","test":"test/frontier/b2-limits.accept.mjs"},{"id":"limit-per-week","text":"Each meeting type can limit bookings per week, with weeks running Monday to Sunday.","test":"test/frontier/b2-limits.accept.mjs"},{"id":"limit-per-month","text":"Each meeting type can limit bookings per month.","test":"test/frontier/b2-limits.accept.mjs"},{"id":"limits-at-confirm","text":"Booking limits are applied again when a booking is confirmed.","test":"test/frontier/b2-limits.accept.mjs"},{"id":"location-per-type","text":"Each meeting type has its own location: Google Meet, in person, a phone call in either direction, or custom text.","test":"test/frontier/b3-location.accept.mjs"},{"id":"guest-phone-field","text":"On types where the host calls the guest, the booking page asks the guest for a phone number.","test":"test/frontier/b3-location.accept.mjs"},{"id":"link-only-types","text":"A meeting type can be offered only by direct link, and the booking page then lists the other types.","test":"test/frontier/b4-link-only.accept.mjs"},{"id":"direct-type-link","text":"A direct link of the form /b/<handle>?type=<id> opens that meeting type.","test":"test/frontier/b4-link-only.accept.mjs"},{"id":"rate-limiting","text":"Booking requests are rate limited per visitor and host page, and a limited request receives a retry-after answer.","test":"test/frontier/a3-abuse.accept.mjs"},{"id":"google-oauth-scopes","text":"Google Calendar connects with OAuth, using the calendar.events and calendar.freebusy scopes.","test":"test/unproven-claims.test.mjs"},{"id":"answers-in-email-and-event","text":"Every answer to a custom question appears in the host's confirmation email and on the calendar event.","test":"test/unproven-claims.test.mjs"},{"id":"web-calendar-views","text":"The calendar client at /calendar runs in the browser on any operating system, with agenda, day, week, month, quarter, and year views over your Google calendars.","test":"test/claims-match-product.test.mjs"},{"id":"multiple-calendars","text":"Every calendar you grant is listed with its own color, and you can show or hide each one.","test":"test/calproviders.test.mjs"},{"id":"event-editing","text":"Events are created, edited, and deleted from the client.","test":"test/frontier/a2-telemetry.accept.mjs"},{"id":"repeating-events","text":"Repeating events use RFC 5545 RRULE (daily, weekly, every 2 weeks, monthly, yearly) and are described back in plain English, with the next occurrences previewed before saving.","test":"test/recurrence.test.mjs"},{"id":"recurrence-dst","text":"A repeating 9am meeting stays at 9am across a daylight-saving change, because recurrence is generated in the event's own time zone.","test":"test/recurrence.test.mjs"},{"id":"incremental-sync","text":"The client mirrors each calendar with Google's own incremental sync tokens and re-baselines automatically when a token expires or its window runs out.","test":"test/calsync.test.mjs"},{"id":"nl-title-intact","text":"Natural-language entry keeps the event title intact.","test":"test/nlp.test.mjs"},{"id":"nl-asks-vague-time","text":"When a phrase is vague, such as \"in the evening\", natural-language entry asks for the time.","test":"test/calendar-render.test.mjs"},{"id":"nl-fallback-labeled","text":"When the language model is unavailable, a simple pattern reader takes over and the interface says so.","test":"test/calendar-render.test.mjs"},{"id":"grid-pinned","text":"The calendar grid is FullCalendar (MIT), pinned by exact version and subresource-integrity hash.","test":"test/calendar-render.test.mjs"},{"id":"calendars-free-tier","text":"Showing and hiding calendars is saved on the free tier.","test":"test/unproven-claims.test.mjs"},{"id":"drag-writes-times","text":"Drag to move and drag to resize write just the times, so moving a meeting keeps its description, attendees, and color.","test":"test/unproven-claims.test.mjs"},{"id":"sync-state-shown","text":"The client states when it last synced, and which calendar failed if one did.","test":"test/unproven-claims.test.mjs"},{"id":"nl-language-model","text":"Natural-language entry is powered by a language model.","test":"test/unproven-claims.test.mjs"},{"id":"coord-negotiation","text":"Group coordination at /c/<handle> lets N people converge on one contiguous block inside a window the coordinator sets.","test":"test/coordinate.test.mjs"},{"id":"coord-gate","text":"Each member holds a personal capability link, and an anonymous visitor sees a gate with the title only.","test":"test/coordinate.test.mjs"},{"id":"coord-privacy","text":"Members see aggregate counts per slot, and each person's busy times and email stay with that person.","test":"test/coordinate.test.mjs"},{"id":"coord-painted-grid","text":"Members paint their availability on a grid.","test":"test/coordinate.test.mjs"},{"id":"coord-travel-ical","text":"A member can add any travel iCal feed, such as Trip Underway or TripIt, and all-day travel events block the whole day window.","test":"test/coordinate.test.mjs"},{"id":"coord-ranking","text":"Candidate blocks are ranked live by how many members are free for the whole block, with quorum shown.","test":"test/coordinate.test.mjs"},{"id":"coord-ties","text":"When two blocks tie at the top, both are surfaced to the coordinator to decide.","test":"test/coordinate.test.mjs"},{"id":"coord-decide-books","text":"Deciding a block books one Google event with every member as an attendee and a Meet link.","test":"test/coordinate.test.mjs"},{"id":"coord-google-freebusy","text":"A member's Google free/busy is merged into their availability on the server.","test":"test/unproven-claims.test.mjs"},{"id":"coord-block-threads","text":"Every candidate block has its own comment thread.","test":"test/unproven-claims.test.mjs"},{"id":"coord-decide-without-google","text":"When the coordinator has no Google connection, the decision still stands and every member is emailed that the coordinator will send the calendar invite.","test":"test/unproven-claims.test.mjs"},{"id":"standing-say-once","text":"Say a scheduling rule once, in plain English (\"keep Friday afternoons clear\", \"no meetings before 9am\", \"nothing after 6pm on weekdays\", \"keep meetings under 90 minutes\"), and it keeps applying.","test":"test/standing.test.mjs"},{"id":"standing-restated","text":"Each rule is restated back in plain words so you can see it was understood correctly.","test":"test/standing.test.mjs"},{"id":"standing-prevent","text":"Prevent: a rule becomes real busy time on your booking page, so nobody can book into a window you protected.","test":"test/standing.test.mjs"},{"id":"standing-enforced-at-confirm","text":"Rules are enforced where slots are displayed and again where a booking is confirmed, so a direct request meets the same rules.","test":"test/calproviders.test.mjs"},{"id":"standing-surface","text":"Surface: meetings already on your calendar that break a rule are listed for you to handle.","test":"test/standing.test.mjs"},{"id":"standing-duration-cap","text":"A meeting type longer than your duration cap shows no bookable times.","test":"test/unproven-claims.test.mjs"},{"id":"standing-organizer","text":"Declining someone else's meeting, or writing to its organizer, stays your decision.","test":"test/unproven-claims.test.mjs"}],"pricing":{"free":true,"freeGroupPolls":{"openAtOnce":3,"peopleEach":10}}}