{
  "icp": "service businesses already running on Google Calendar",
  "capabilities": {
    "availability": {
      "headline": "Books appointments straight into Google Calendar.",
      "lede": "Reads real availability from Google Calendar, books the right service for the right duration, and writes the appointment back to the right calendar — all inside the conversation.",
      "cards": [
        {
          "num": "A.01",
          "title": "Knows when you're free, even at 2am",
          "body": "Reads live availability from Google Calendar — including buffer times, working hours, and existing events. No double-bookings, no manual calendar checks."
        },
        {
          "num": "A.02",
          "title": "Books the right service for the right duration",
          "body": "A 30-minute consult lands as 30 minutes. A 4-hour treatment lands as 4 hours. The agent maps caller intent to the right Google Calendar event template before booking."
        },
        {
          "num": "A.03",
          "title": "Confirms in the customer's timezone",
          "body": "Caller in London, business in New York — the agent handles the timezone math, books in Google Calendar's UTC, and confirms back to the caller in their local time."
        }
      ],
      "apiSummary": "The agent calls two Google Calendar tools: one returns open slots in the invitee's timezone; the other creates or finds the contact and writes the appointment back to the right Google Calendar.",
      "tools": [
        "getGoogleCalendarAvailability",
        "createGoogleCalendarContactAppointment"
      ],
      "curl1Path": "/mcp/tools/getGoogleCalendarAvailability",
      "curl2Path": "/mcp/tools/createGoogleCalendarContactAppointment"
    },
    "lifecycle": {
      "headline": "Owns the full booking lifecycle inside Google Calendar.",
      "lede": "Every \"can I move my Tuesday?\" or \"actually, cancel that\" lands with the receptionist instead of on your desk — and every change is written back to Google Calendar with a reason on the event.",
      "cards": [
        {
          "num": "B.01",
          "title": "Finds the booking by email — no IDs to remember",
          "body": "Customers don't quote event IDs over the phone. The agent searches Google Calendar by the caller's email and reads back date, time, and service before changing anything."
        },
        {
          "num": "B.02",
          "title": "Reschedules in one turn — no cancel-then-rebook round-trip",
          "body": "The agent moves the existing Google Calendar event to the new slot in a single confirmation. The original event is preserved on failure so a botched reschedule never leaves the customer with nothing."
        },
        {
          "num": "B.03",
          "title": "Cancels with a reason on the record",
          "body": "Every cancellation writes the customer's reason onto the Google Calendar event description — so the next time you look at the day, you know why the slot opened up."
        }
      ],
      "apiSummary": "Search, reschedule, and cancel all accept just an email. The soonest upcoming Google Calendar event for that email is resolved server-side — no event UUIDs at the agent layer.",
      "tools": [
        "searchGoogleCalendarAppointments",
        "rescheduleGoogleCalendarAppointment",
        "cancelGoogleCalendarAppointment"
      ],
      "curl1Path": "/mcp/tools/searchGoogleCalendarAppointments",
      "curl2Path": "/mcp/tools/rescheduleGoogleCalendarAppointment",
      "curl3Path": "/mcp/tools/cancelGoogleCalendarAppointment"
    },
    "routing": {
      "headline": "Routes every caller to the right person, for the right service.",
      "lede": "Google Calendar doesn't model staff, services, prices, or expertise — it only models events on calendars. At setup we capture your team into our roster store: who each specialist is, which calendar is theirs, what they're good at, what they charge, how long each service takes. The agent reads <em>that</em> roster at call time and books on the right specialist's Google Calendar.",
      "cards": [
        {
          "num": "C.01",
          "title": "Routes by specialist by name or expertise",
          "body": "\"I want Sarah for a balayage\" routes to Sarah's Google Calendar. \"Just whoever's free for a haircut\" checks every stylist who offers haircuts and presents the soonest slot across all of them."
        },
        {
          "num": "C.02",
          "title": "Per-specialist availability and pricing",
          "body": "Each staff member's Google Calendar exposes their services, prices, durations, and personal availability. The agent never quotes a price that isn't this specialist's, or a slot that isn't on this specialist's calendar."
        },
        {
          "num": "C.03",
          "title": "Falls back to the next available specialist",
          "body": "Specialist of choice has no openings in the caller's window? The agent offers the next available person who does the same service — and confirms the swap before booking."
        }
      ],
      "apiSummary": "Roster and services live in our store, not Google Calendar — because Google Calendar can't represent them. At setup, you (or we) write each specialist's name, bio, expertise, languages, timezone, location, role, and their Google Calendar identifier into the roster; services (name, price, duration) are written alongside. One call at runtime returns the full roster with each specialist's services attached — the agent matches caller intent → specialist → service in a single hop, then checks live availability against that specialist's actual Google Calendar.",
      "tools": [
        "listGoogleCalendarTeamMembers",
        "getGoogleCalendarSpecialistServices",
        "createGoogleCalendarTeamMember",
        "createGoogleCalendarService"
      ],
      "curl1Path": "/mcp/tools/listGoogleCalendarTeamMembers",
      "curl2Path": "/mcp/tools/getGoogleCalendarSpecialistServices"
    }
  },
  "setup": {
    "headline": "Setup in 3 steps. Battle-tested on real <span data-tpl-crm>Google Calendar</span> businesses.",
    "lede": "You connect <span data-tpl-crm>Google Calendar</span> once, the agent imports your team and your services, and you're answering calls the same afternoon. No Zapier, no n8n, no glue code, no prompt-engineering by you.",
    "steps": [
      {
        "num": "S.01",
        "title": "Connect Google Calendar (OAuth, 60 seconds)",
        "body": "One Google sign-in grants read/write to the calendars you select. Pick the staff calendars you want bookable; leave personal calendars alone. Revocable any time from your Google account."
      },
      {
        "num": "S.02",
        "title": "Import roster, services & durations",
        "body": "The agent imports every selected calendar as a bookable specialist and reads service definitions (name, duration, price) from the templates you already use. You confirm; you don't re-enter. If you don't have services yet, we create a default set you can edit in the dashboard."
      },
      {
        "num": "S.03",
        "title": "Drop the agent on your phone line and your site",
        "body": "Forward your business number to the agent's number and paste the chat widget into your site. The same agent — same roster, same calendar, same rules — answers both. Live the same afternoon."
      }
    ],
    "nativeAlternative": {
      "headline": "Why not just use Google Calendar's <strong>Appointment Schedules</strong>?",
      "body": "Google's <strong>Appointment Schedules</strong> are great at one thing: a customer who already knows what they want, on a device, clicking a public booking link. They stop where the real work starts — they don't answer the phone, they don't talk to walk-ins on chat, they don't route \"I want Sarah for a balayage\" vs \"whoever's free for a haircut\", they don't reschedule by email, they don't speak 30 languages, and they don't write a cancellation reason back onto the event. The agent is the layer above: it talks to humans on voice and chat, then writes the clean result into the same Google Calendar you're already running."
    },
    "enrichmentSummary": "Every tool the agent calls is an opinionated wrapper over the raw Google Calendar API. Each one does the messy work (UUID resolution, timezone math, pagination, error normalisation) before the LLM ever sees a response — so the agent reasons over clean, AI-aligned payloads instead of raw calendar internals.",
    "enrichmentExamples": [
      {
        "title": "Booking an appointment",
        "raw": "<code>events.insert</code> needs calendarId, ISO-8601 start/end with offsets, attendee email list, conference data, reminders, source, extendedProperties. Caller has to compute end-time from a service duration, format the timezone, and know which calendar maps to which staff member.",
        "mcp": "<code>createGoogleCalendarContactAppointment</code> accepts <code>email</code>, <code>scheduled_datetime</code> (naive — no offset), <code>invitee_timezone</code>, and <code>event_type_uuid</code>. Server resolves the right staff calendar, computes end-time from the service duration, adds the customer as attendee, returns both local and UTC start times in the response."
      },
      {
        "title": "Finding an existing booking to change",
        "raw": "<code>events.list</code> requires calendarId, timeMin, timeMax, q, singleEvents, orderBy, pageToken — across every calendar you care about. The caller paginates, filters by email in the attendees array, and decides which calendar to check.",
        "mcp": "<code>searchGoogleCalendarAppointments</code> takes just an <code>email</code>. Server fans out across every connected calendar, filters by attendee, returns only upcoming events with event type name, start time, and status — already sorted soonest-first."
      },
      {
        "title": "Cancelling with a reason",
        "raw": "<code>events.delete</code> needs the calendarId and eventId. The cancellation reason has nowhere to go — you'd need a follow-up <code>events.patch</code> to write it into the description before deleting, and the deletion is irreversible.",
        "mcp": "<code>cancelGoogleCalendarAppointment</code> takes <code>email</code> + <code>reason</code>. Server resolves the soonest event, writes the reason onto the event description, then cancels — atomically, with a single response containing the cancelled event UUID and the recorded reason."
      }
    ],
    "alignmentSummary": "Every Google Calendar MCP tool follows the same AI-alignment contract, so the agent never has to think about transport:",
    "alignment": [
      "<strong>Naive datetimes in, ISO-8601 out.</strong> The agent passes <code>2026-05-15T11:00:00</code> + a timezone string. We do the offset math.",
      "<strong>Email is the identity.</strong> Cancel and reschedule never need an event UUID at the agent layer — email + soonest upcoming resolves server-side.",
      "<strong>Flat, deterministic shapes.</strong> Every response has the same top-level keys across every tool, so the agent's prompt never grows with edge-case branching.",
      "<strong>Human-readable date labels.</strong> Responses include <code>\"Friday, May 15, 2026\"</code> next to the ISO string, so the agent reads time back to the caller without reformatting.",
      "<strong>Errors are messages, not codes.</strong> A 4xx becomes a one-sentence reason the agent can repeat to the caller without translation.",
      "<strong>Idempotent reschedules.</strong> If a reschedule fails mid-flight, the original Google Calendar event is preserved — the customer never ends up with nothing."
    ],
    "industryLine": "Currently running for <strong>salons, clinics, contractors, consultancies, small agencies, tutors, coaches, and solo operators</strong> — anyone whose calendar is in Google but whose phone keeps ringing after hours.",
    "teamsSetup": {
      "headline": "Multi-specialist setup — roster, services &amp; system-prompt assembly",
      "body": "If you run more than one staff member, setup imports the roster once, links each specialist to the services they actually offer, and bakes the result into the agent's system prompt at setup time — not at runtime. The agent doesn't query your roster on every call; it already knows who does what.",
      "steps": [
        "<strong>Roster import.</strong> The setup workflow calls <code>listGoogleCalendarOrganisationMembers</code> once, then writes each specialist into our Firestore directory keyed by <code>crm_user_id</code> (with name, role, timezone, scheduling URL).",
        "<strong>Per-specialist services.</strong> For each specialist, <code>getGoogleCalendarUserProfile</code> returns their active event types (name, duration, price, <code>event_type_uuid</code>). One call per person, cached.",
        "<strong>Service visibility.</strong> Each service is flagged <em>Public</em>, <em>Private</em> or <em>Ignored</em> — the agent only quotes and books Public ones. You toggle this in the dashboard without re-deploying.",
        "<strong>System-prompt assembly.</strong> The cached specialist + service JSON is prepended to the agent's system prompt before the humaniser splits (personality, etiquettes, tone, speech style) — so the agent reads the roster before it reads its own instructions.",
        "<strong>Runtime stays minimal.</strong> On a live call the agent makes at most one availability call and one booking call — never a roster lookup. Updates to specialists or services re-run the cache; the agent picks them up on its next deploy."
      ],
      "note": "The end result: the agent can match \"I want Sarah for a balayage\" → Sarah's <code>event_type_uuid</code> for balayage → Sarah's calendar availability → a booking on Sarah's calendar, without a single roster query during the call."
    }
  },
  "privacy": {
    "headline": "Your <span data-tpl-crm>Google Calendar</span> data passes through. It doesn't stick.",
    "lede": "We process your <span data-tpl-crm>Google Calendar</span> data to answer the call — then we forget it. The only thing we persist is a conversation history ID so the agent can recognise a returning caller. Bookings, availability, attendees, services, your roster — all of it stays in your Google Calendar, owned by your Google account.",
    "cards": [
      {
        "kind": "stored",
        "label": "What we store",
        "body": "<strong>Conversation history IDs only.</strong> So the agent can pick up where it left off if a caller hangs up and rings back. No call audio, no transcripts of your bookings, no caller PII."
      },
      {
        "kind": "not-stored",
        "label": "What we don't",
        "body": "Caller names, emails, phone numbers, your staff roster, your services, your appointment history, payment details, calendar contents. None of it. The MCP layer reads what it needs, hands it to the LLM, and discards it."
      },
      {
        "kind": "data-lives",
        "label": "Where data lives",
        "body": "<strong>In your Google Calendar, in your Google account.</strong> Cancellation reasons land on the event description. Attendee emails land on the event. We don't build a shadow database alongside yours."
      },
      {
        "kind": "revoke",
        "label": "Revocation",
        "body": "Disconnect the integration in your Google account and the agent loses access immediately. There is no \"export your data\" step because there is no data to export — it was never ours to hold."
      }
    ],
    "scopesSummary": "We request the smallest possible OAuth scope set for Google Calendar — only what the booking lifecycle requires, nothing for analytics, nothing for marketing.",
    "scopes": [
      "<code>calendar.events</code> — read and write events on the calendars you select (this is the booking work).",
      "<code>calendar.calendarlist.readonly</code> — read your list of calendars so setup can show you which ones to make bookable.",
      "<code>calendar.events.freebusy</code> — read free/busy windows for availability checks without reading event details on calendars you didn't connect.",
      "<strong>Not requested:</strong> Gmail, Drive, Contacts, profile data beyond your email address."
    ],
    "surfaceNote": "Same scopes you'd grant any calendar tool — but a smaller surface. The MCP layer holds the token; the LLM never sees it, and every tool call is logged with the operation name, never the raw payload."
  },
  "failureModes": [
    {
      "title": "Double-booking",
      "raw": "Raw <code>events.insert</code> on Google Calendar will happily write any time you give it — even a time another customer just took. With a vanilla \"ChatGPT plus a calendar plugin\" setup, two callers on hold at the same moment can both walk away with the same 11:00am slot.",
      "mcp": "<code>createGoogleCalendarContactAppointment</code> checks availability inside the booking call itself. An already-taken slot returns an error before the agent can confirm, so the agent says \"that one just went — can I offer 11:30?\" instead of confirming a collision."
    },
    {
      "title": "Inventing services that don't exist",
      "raw": "Raw Google Calendar has no concept of \"haircut\" or \"$50\" — it's just events with titles. A naive agent will make up a service name or quote a price it pulled out of thin air, because there's nothing in the API stopping it.",
      "mcp": "Setup bakes your real services (name, duration, price, <code>event_type_uuid</code>) into the agent's system prompt as a frozen table. The agent <em>can only</em> quote services that exist at prices that exist. There is no \"close enough\" — the only event types it can book are the ones you defined."
    },
    {
      "title": "Hallucinated reschedules and cancels",
      "raw": "Raw <code>events.delete</code> has nowhere to record a reason. A weak agent says \"okay, I've cancelled that\" and either (a) didn't actually cancel anything or (b) cancelled the wrong event, with no audit trail.",
      "mcp": "<code>cancelGoogleCalendarAppointment</code> requires both an email and a reason. The reason is written to the event description before the cancel completes, atomically — so every change is logged inside Google Calendar, attributable to the call, and visible to you on the timeline."
    },
    {
      "title": "Timezone drift (\"I booked you for 3pm\" — actually 3pm UTC)",
      "raw": "Raw Google Calendar demands ISO offsets with DST baked in. Get the offset wrong by an hour and the customer shows up at the wrong time. This is the single most common failure of consumer-grade AI scheduling.",
      "mcp": "The agent never sees an offset. It passes naive datetime (<code>2026-05-15T11:00:00</code>) plus the caller's IANA timezone (<code>America/New_York</code>). The MCP layer does the offset math, including DST transitions, and writes a correct ISO time into Google Calendar. The agent can't get it wrong because it never holds the wrong representation."
    },
    {
      "title": "Cancelling the wrong person's appointment",
      "raw": "Raw Google Calendar needs an event UUID to cancel. If the agent fishes the wrong UUID out of a list — or worse, makes one up — it cancels someone else's appointment. There is no identity gate.",
      "mcp": "<code>cancelGoogleCalendarAppointment</code> and <code>rescheduleGoogleCalendarAppointment</code> resolve by email and pick the soonest upcoming event. The humaniser prompt requires the agent to verify the caller's name and email against the booking before any change. The agent literally cannot cancel without that match."
    }
  ],
  "failureModesMeta": {
    "headline": "How most AI receptionists fail on <span data-tpl-crm>Google Calendar</span> — and why ours can't.",
    "lede": "Most AI receptionists fail in the same five ways. Ours can't, because the failure was solved one layer down — in the API the agent talks to, not in the prompt. The agent is honest because the API doesn't let it lie.",
    "closer": "The agent is honest because the API doesn't let it lie."
  },
  "faqs": [
    {
      "q": "Does this actually work with my Google Calendar?",
      "a": "Yes — the agent reads availability and writes appointments to whichever Google Calendar you connect. Notes, attendee, start time, end time and event description all land on the right event, in the right calendar."
    },
    {
      "q": "Will this be able to find specialists/staff from my Google Calendar setup?",
      "a": "Yes. If each staff member has their own Google Calendar, the agent reads the roster, knows what services each person offers, and routes the caller accordingly. One shared calendar works too — the agent simply books into that one."
    },
    {
      "q": "Can it cancel a Google Calendar appointment from a phone call?",
      "a": "Yes. The caller gives their email, the agent finds the soonest upcoming Google Calendar event for that email, reads it back, and cancels with a reason written onto the event description."
    },
    {
      "q": "What if a customer has two upcoming bookings in my Google Calendar?",
      "a": "The agent lists every upcoming Google Calendar appointment for that email — date, time, and service — and asks which one to change before doing anything. It never assumes."
    },
    {
      "q": "Does it handle Google Calendar timezones correctly?",
      "a": "Yes. The agent confirms the caller's country/timezone, books in Google Calendar's UTC, and reads the time back in the caller's local timezone. No customer-facing UTC strings, no off-by-an-hour confirmations."
    },
    {
      "q": "Will customers know it's an AI?",
      "a": "Not on voice — the bundled humaniser prompts add natural pacing, filler words, and warmth. On chat, we recommend a small \"AI assistant\" badge so trust stays intact. Either way, bookings still land cleanly in Google Calendar."
    },
    {
      "q": "How long until it's actually answering calls and writing to Google Calendar?",
      "a": "Most owners are live the same afternoon. The Google Calendar connection takes a few minutes; the phone integration is usually under an hour. Web chat is faster."
    }
  ]
}