# IntoCal > IntoCal is a scheduling platform for people, teams and AI agents: booking pages, Outlook and Google sync, team round-robin, one-line embeds and AI bookings via MCP. Every user gets a hosted MCP server. ## Positioning IntoCal is the cleanest Outlook-first booking tool. It replaces Calendly, Microsoft Bookings, Koalendar, Cal.com, and TidyCal for people who want a beautiful personal booking page at `intocal.com/u/{username}`, native Microsoft 365 sync, team scheduling without enterprise pricing, and native AI-agent bookings via the Model Context Protocol. ## Positioning vs competitors - **vs Calendly**: cheaper Pro ($10/mo vs $12/mo), better native Outlook, one-line JS embed, MCP for AI agents built in. - **vs Microsoft Bookings**: keeps M365 sync but replaces the dated booking-page UI with a modern embeddable widget. - **vs Cal.com**: same feature set without self-hosting or ops burden; MCP hosted per-user. - **vs Koalendar**: adds native Outlook, team round-robin, webhooks, and API — all on the free tier. - **vs TidyCal**: modern subscription with active MCP and Outlook support; TidyCal is stuck on lifetime-deal features. ## Product summary IntoCal lets users create booking calendars, define event types, set availability, and share a public booking page. Guests can book meetings without needing an account. ## Pages - [Home](/): Scheduling infrastructure for people and AI agents. - [Pricing](/pricing): Plans, limits, and subscription details. - [About](/about): Why we built IntoCal and the team behind it. - [Blog](/blog): Guides, comparisons, and product updates. - [MCP for AI agents](/mcp): Connect Claude, ChatGPT, Cursor, and other agents to hosted IntoCal MCP servers. - [AI booking hub](/ai): Book meetings through AI assistants. - [Calendly alternative](/alternatives/calendly): Feature and pricing comparison with Calendly. - [For Outlook users](/for/outlook-users): Native Microsoft 365 calendar sync and booking pages. - [For agencies](/for/agencies): Team scheduling, round-robin, and embeddable booking widgets. ## MCP (Model Context Protocol) Every IntoCal user has a hosted MCP server. AI agents (Claude, ChatGPT, Cursor, Codex, Copilot, Windsurf, Warp) can connect natively — no install. Endpoint pattern: `https://api.intocal.com/mcp/{username}` Transport: Streamable HTTP, JSON-RPC 2.0 Protocol version: 2025-06-18 Discovery: `https://intocal.com/.well-known/mcp.json` Landing page: `https://intocal.com/mcp` Auth: `Authorization: Bearer ` for owner-mode (full tools, auto-confirmed bookings). Unauthenticated calls work in public-mode with a limited toolset; those bookings are held pending until the guest clicks a confirmation link. Tools: `list_event_types`, `query_slots` (accepts `member_ids[]` and `filter.tag` for team events), `request_booking`, `list_hosts_for_event`, `book_with_host`, `create_booking` (owner), `list_team_members` (owner), `list_bookings` (owner), `cancel_booking` (owner). ## API IntoCal provides a resource-oriented REST API under `/v1`. Base URL: `https://api.intocal.com/v1` ### Authentication Optional API key via `Authorization: Bearer `. Public read endpoints work without auth. Write endpoints (cancel, reschedule) require either API key or guest_email verification. ### Response envelope Success: `{ "ok": true, "data": { ... } }` Error: `{ "ok": false, "error": { "code": "...", "message": "...", "suggested_action": "..." } }` ### Idempotency Write endpoints accept `Idempotency-Key` header. Required for: create booking, cancel booking, reschedule booking. ### Endpoints #### 1. List event types ``` GET /v1/event-types?host_id={host_id} ``` Returns active event types, optionally filtered by host. #### 2. Get host availability ``` GET /v1/hosts/{host_id}/availability ``` Returns weekly availability rules and date overrides. #### 3. Query available slots ``` POST /v1/slots/query Content-Type: application/json { "event_type_id": "uuid", "host_id": "uuid", "from": "2026-03-24T00:00:00Z", "to": "2026-03-25T00:00:00Z", "timezone": "Europe/Tallinn" } ``` Returns computed slots respecting duration, buffers, min notice, max booking window. #### 4. Create booking ``` POST /v1/bookings Idempotency-Key: unique-key Content-Type: application/json { "event_type_id": "uuid", "host_id": "uuid", "slot_start": "2026-03-24T13:00:00Z", "timezone": "Europe/Tallinn", "invitee": { "name": "Jane Doe", "email": "jane@example.com" }, "metadata": { "source": "agent" } } ``` #### 5. Get booking ``` GET /v1/bookings/{booking_id} ``` #### 6. Cancel booking ``` POST /v1/bookings/{booking_id}/cancel Content-Type: application/json { "reason": "Invitee requested cancellation", "guest_email": "jane@example.com" } ``` Guests can also cancel themselves from a signed link in their confirmation email (`https://intocal.com/booking/cancel?token=…`) — no API key needed. Hosts and agents use the endpoint above. #### 7. Reschedule booking ``` POST /v1/bookings/{booking_id}/reschedule Content-Type: application/json { "new_slot_start": "2026-03-25T15:00:00Z", "timezone": "Europe/Tallinn", "guest_email": "jane@example.com" } ``` ## Booking Flow 1. `GET /v1/event-types?host_id=...` — discover bookable event types 2. `POST /v1/slots/query` — find open slots for a date range 3. `POST /v1/bookings` — create the booking 4. `GET /v1/bookings/{id}` — retrieve confirmation ## Error Codes - `VALIDATION_ERROR` — invalid input - `NOT_FOUND` — resource not found - `UNAUTHORIZED` — auth required - `FORBIDDEN` — insufficient permissions - `HOST_INACTIVE` — host not accepting bookings - `EVENT_TYPE_INACTIVE` — event type disabled - `SLOT_NOT_AVAILABLE` — slot taken or outside booking window - `BOOKING_ALREADY_CANCELED` — already canceled - `BOOKING_NOT_RESCHEDULABLE` — cannot reschedule - `INVALID_TIMEZONE` — unrecognized IANA timezone - `RATE_LIMITED` — too many requests - `INTERNAL_ERROR` — server error ## Integrations & Webhooks API (auth required) #### 8. List integrations ``` GET /v1/integrations Authorization: Bearer ``` #### 9. Create integration ``` POST /v1/integrations { "provider": "google_calendar|outlook|zoom|stripe|webhook|zapier|make|automateo|n8n", "config": {} } ``` #### 10. Delete integration ``` DELETE /v1/integrations/{id} ``` #### 11. List webhook endpoints ``` GET /v1/webhooks ``` #### 12. Create webhook endpoint ``` POST /v1/webhooks { "url": "https://...", "events": ["booking.created", "booking.canceled", "booking.rescheduled"], "provider": "generic" } ``` #### 13. Update webhook endpoint ``` PATCH /v1/webhooks/{id} { "url": "...", "events": [...], "is_active": true } ``` #### 14. Delete webhook endpoint ``` DELETE /v1/webhooks/{id} ``` #### 15. View webhook delivery logs ``` GET /v1/webhooks/{id}/logs ``` #### 16. Send test event ``` POST /v1/webhooks/{id}/test ``` ### Webhook Events IntoCal dispatches these events to configured webhook endpoints: - `booking.created` — a new booking was confirmed - `booking.canceled` — a booking was canceled - `booking.rescheduled` — a booking was moved to a new slot Payloads are POST'd with these headers: - `X-IntoCal-Event` — the event name - `X-IntoCal-Signature` — `sha256=` for payload verification - `X-IntoCal-Timestamp` — ISO-8601 delivery time - `X-IntoCal-Delivery` — unique delivery ID ### Supported Integrations - **Google Calendar** — two-way sync, busy-time detection - **Microsoft Outlook** — two-way sync via Microsoft Graph - **Zoom** — auto-create meeting links on booking - **Stripe** — payment collection on booking, refund on cancel - **Webhook** — generic HTTP POST to any URL - **Zapier** — trigger zaps on booking events - **Make.com** — trigger scenarios on booking events - **Automateo** — trigger workflows on booking events - **n8n** — trigger webhook nodes on booking events ## SDK Usage (TypeScript) ```typescript const BASE = "https://api.intocal.com/v1"; const headers = { "Content-Type": "application/json", "Authorization": "Bearer YOUR_API_KEY" }; // List event types const types = await fetch(`${BASE}/event-types?host_id=HOST_ID`, { headers }).then(r => r.json()); // Query slots const slots = await fetch(`${BASE}/slots/query`, { method: "POST", headers, body: JSON.stringify({ event_type_id: "...", host_id: "...", from: "...", to: "...", timezone: "Europe/Tallinn" }) }).then(r => r.json()); // Create booking const booking = await fetch(`${BASE}/bookings`, { method: "POST", headers: { ...headers, "Idempotency-Key": crypto.randomUUID() }, body: JSON.stringify({ event_type_id: "...", host_id: "...", slot_start: "...", timezone: "Europe/Tallinn", invitee: { name: "Jane", email: "jane@example.com" } }) }).then(r => r.json()); // Create webhook const webhook = await fetch(`${BASE}/webhooks`, { method: "POST", headers, body: JSON.stringify({ url: "https://your-app.com/webhooks", events: ["booking.created"], provider: "generic" }) }).then(r => r.json()); // List integrations const integrations = await fetch(`${BASE}/integrations`, { headers }).then(r => r.json()); ``` ## OpenAPI Spec Available at: /api/openapi.json ## AI Plugin Available at: /.well-known/ai-plugin.json