Unified Calendar API Quickstart: A Concise Reference for B2B SaaS
A complete technical blueprint and quickstart for the Unified Calendar API. Learn how to ship normalized Google Calendar and Outlook integrations in days.
Your product team just committed to shipping a two-way calendar sync by the end of the quarter. If your engineering roadmap says "add Google Calendar and Outlook integration this quarter," you have two paths. You can spend the next three months wiring up Microsoft Graph, the Google Calendar API, OAuth refresh logic, free/busy aggregation, and provider-specific webhook plumbing from scratch. Or, you can hit a single unified endpoint that returns a normalized event payload regardless of the underlying provider.
Building native integrations for Google Calendar and Microsoft Outlook is a trap. Between OAuth token refresh failures, differing recurrence rules, and undocumented edge cases, calendar integrations are notoriously hostile to build and maintain. The solution is to abstract the complexity behind a normalized schema.
This guide is the concise reference for the second path—a blueprint you can hand to your engineering team on a Monday and have shipping by Friday. We will cover the architectural realities of scheduling data, how to correctly handle provider rate limits, the exact API calls needed for a quickstart, and how to expose this data to AI agents via the Model Context Protocol (MCP).
The Business Case for a Unified Calendar API
A unified calendar API is an abstraction layer that translates the proprietary data models and authentication flows of multiple calendar providers (Google, Microsoft, Apple) into a single, standardized REST interface.
Building custom API integrations from scratch is a massive capital expense. Independent development agencies estimate that building a single secure, well-documented custom API integration costs an average of $15,000 to $20,000. For complex enterprise calendar integrations, that cost easily exceeds $80,000 per provider. And that is just the initial build. The hidden cost is the ongoing maintenance burden, which typically runs 15% to 25% of the original cost annually.
Calendar work tends to land at the higher end of these estimates because the abstractions are genuinely messy. When you integrate Google Calendar and Outlook directly, your backend engineers are forced to maintain state machines for two completely different systems. Google uses specific pagination tokens and webhooks that require domain verification. Microsoft Graph has its own idiosyncrasies regarding timezone handling and recurring event expansions.
Then come the operational tax items:
- Rate limits: Google Calendar's quota system frequently returns HTTP 429 on bulk sync workloads, forcing you to build request queueing and per-user quota tracking. Microsoft Graph throttles at unpredictable thresholds that vary by tenant and endpoint.
- Webhook fragmentation: Google's push notifications expire and need renewal. Microsoft Graph subscriptions cap at three days for most resources. Apple Calendar (CalDAV) has no real webhook story.
- OAuth refresh: Tokens expire mid-sync. Your sync job needs to coordinate refresh across concurrent workers, or you will DoS your own integration with 401 Unauthorized storms.
- Schema drift: Google adds fields. Microsoft renames properties. Your mapping code breaks at 2 AM.
By leveraging a pass-through unified API, you eliminate integration-specific code. Your application makes a single request to a normalized endpoint, and the API layer dynamically maps that request into the provider's native format. This architectural approach to integrating multiple calendar services shifts your engineering focus from maintaining third-party infrastructure to building core product features.
If you're comparing options at the platform level, the best unified calendar APIs for B2B SaaS and AI agents walks through the broader landscape. This post is the quickstart for teams that have already decided to abstract the layer away.
Core Entities: Calendars, Events, and Availability
Schema normalization is the process of mapping disparate third-party data structures into a predictable, canonical format.
Every calendar platform stores events, attendees, and availability data differently. To build a reliable scheduling feature, you must understand how a unified API categorizes this data into logical domains. The Truto Unified Calendar API exposes three primary entities and three supporting ones. Every calendar provider eventually maps into this shape:
| Entity | Purpose | Maps to (examples) |
|---|---|---|
| Calendars | The primary ledger/container for time-based entries | Google Calendar lists, Outlook calendar groups |
| Events | Individual meetings, appointments, or blocked time slots | Google events, Microsoft events |
| Availability | Calculated free/busy time windows | Google freeBusy, Microsoft getSchedule |
| EventTypes | Pre-configured meeting/booking templates | Calendly event types, HubSpot Meetings |
| Contacts | Participants, attendees, and organizers | Event attendees arrays |
| Attachments | Files attached to events | Google Drive attachments, Outlook attachments |
Here is a deeper look at the core scheduling loop:
1. Core Scheduling
- Calendars: A user might have a "Work Calendar," a "Personal Calendar," and a shared "Team Holidays" calendar. The unified schema abstracts away whether this is a Google Calendar list or an Outlook folder.
- Events: A normalized Event entity handles the heavy lifting of translating start and end times, timezone offsets, and recurrence rules into standard ISO 8601 formats.
2. Availability & Booking
- Availability: Querying this entity is the most computationally expensive part of scheduling, as it requires evaluating overlapping events across multiple calendars and timezones.
- EventTypes: Heavily used in routing platforms to define the parameters of an Event (duration, location, default description) before it is formally booked.
3. Identity & Participation
- Contacts: The participants associated with an Event.
The relationships are straightforward in a typical B2B SaaS scheduling loop:
erDiagram
CALENDAR ||--o{ EVENT : "contains"
EVENT ||--o{ CONTACT : "includes attendees"
EVENT ||--o{ ATTACHMENT : "has"
EVENT_TYPE ||--o{ EVENT : "generates"
CALENDAR ||--o{ AVAILABILITY : "determines"
EVENT_TYPE }|--|| AVAILABILITY : "checks before booking"The non-obvious value here is schema normalization. Schema normalization is the hardest problem in SaaS integrations because edge cases are infinite. A unified model guarantees that whether the underlying provider is Google or Microsoft, your application always receives a start_time, end_time, and an array of attendees in the exact same JSON structure.
Under the hood, Truto's mapping layer translates each provider's native field names to the unified schema using declarative JSONata expressions, not integration-specific code. That means a new calendar provider can be onboarded as a configuration change rather than a code deploy.
How to Handle Rate Limits and Pagination
Rate limiting is the practice of restricting the number of API requests a client can make within a specific timeframe to prevent abuse and ensure system stability.
One of the most common misconceptions about unified APIs is that they magically absorb third-party rate limits. They do not. If your application sends 5,000 requests per second to Google Calendar, Google will reject the traffic, and the unified API will pass that rejection back to you.
This is the most important paragraph in the post, so read it twice. Truto does not silently retry, throttle, or absorb rate limit errors. When an upstream API like Google Calendar or Microsoft Graph returns an HTTP 429 Too Many Requests, Truto passes that error directly to the caller.
However, Truto normalizes the upstream rate limit information into standardized headers following the IETF rate limit headers specification. This means you do not have to parse Google's specific error payload versus Outlook's error payload; you simply read the standard headers:
ratelimit-limit: The maximum number of requests permitted in the current time window.ratelimit-remaining: The number of requests remaining in the current window.ratelimit-reset: The time at which the rate limit window resets (in UTC epoch seconds).
This is a deliberate design choice. Calendar workloads vary enormously—a scheduling product polling availability looks very different from a CRM ingesting meeting history—and a unified retry policy would be wrong for most of them. By surfacing the rate limit state honestly, you can implement exponential backoff strategies that match your actual workload and avoid thundering herd problems.
Implementing Exponential Backoff
When your system receives a 429 response, it should pause execution until the reset time. If a reset time is not available, use a standard exponential backoff with jitter. A minimal client-side handler in TypeScript looks like this:
async function callWithBackoff(url: string, opts: RequestInit, maxRetries = 5) {
let retries = 0;
while (retries < maxRetries) {
const response = await fetch(url, opts);
if (response.status !== 429) {
return response;
}
const resetTime = response.headers.get('ratelimit-reset');
let waitTime;
if (resetTime) {
// Calculate time to wait based on the reset header
const now = Math.floor(Date.now() / 1000);
waitTime = Math.max(0, parseInt(resetTime, 10) - now) * 1000;
} else {
// Fallback to exponential backoff with jitter
waitTime = Math.pow(2, retries) * 1000 + Math.random() * 1000;
}
console.warn(`Rate limited. Retrying in ${waitTime}ms...`);
await new Promise(resolve => setTimeout(resolve, waitTime));
retries++;
}
throw new Error('Max retries exceeded after rate limit.');
}Normalized Pagination
Similarly, pagination varies wildly between providers. Google Calendar uses pageToken, while Microsoft Graph uses @odata.nextLink. The unified API abstracts this by returning a standard next_cursor in the response payload. To fetch the next page, you simply append ?next_cursor=<value> to your subsequent request and keep going until it is null. No special-casing per provider.
If you're hitting rate limits frequently for read-heavy workloads (think: building an availability dashboard across thousands of users), consider pairing the live API with Truto's synced data store via the truto_super_query parameter. That moves the read load off the third-party API entirely. Trade-offs of real-time vs cached unified APIs are worth thinking through before you commit.
Create a Concise API Reference / Quickstart for the Unified Calendar API
When developers evaluate your product's integration capabilities, they look for a copy-pasteable recipe. Publishing developer recipes with runnable code is the highest-leverage way to prove your API works.
Below is the exact blueprint for a unified calendar API quickstart. It covers the end-to-end happy path: connecting an account, listing calendars, querying availability, creating an event, and subscribing to webhooks. All requests target https://api.truto.one/unified/calendar.
Step 1: Authentication and Routing
First, drop the Truto Link UI into your front end. The user picks a provider (Google, Outlook, Calendly, etc.) and completes the OAuth dance. Your back end receives an integrated_account_id via webhook or the Link callback.
This ID represents the specific tenant connection. The unified API uses this ID to route the request to the correct provider and attach the appropriate OAuth access tokens. Token refresh is handled by the platform automatically—tokens are refreshed shortly before they expire, with concurrency control so parallel callers don't trigger refresh storms.
Pass the ID as a query parameter in all subsequent requests:
GET https://api.truto.one/unified/calendar/calendars?integrated_account_id=acc_abc123
Authorization: Bearer YOUR_TRUTO_API_KEYStep 2: List Calendars
Retrieve the normalized calendar containers, including primary calendar status and time zones.
Request:
curl -G "https://api.truto.one/unified/calendar/calendars" \
-H "Authorization: Bearer $TRUTO_API_KEY" \
-d "integrated_account_id=acc_abc123"Response:
{
"result": [
{
"id": "primary",
"name": "Work Calendar",
"is_primary": true,
"time_zone": "America/Los_Angeles",
"remote_data": { "...": "raw provider response" }
}
],
"next_cursor": null,
"result_count": 1
}Note the remote_data object. The unified schema covers what most apps need, but the raw provider payload is always preserved so you can reach for provider-specific fields without falling back to a separate proxy call.
Step 3: Querying Availability
Finding open slots without double-booking is where most native integrations die. Before booking a meeting, you must check if the user is free. The availability endpoint calculates free/busy windows based on existing events across one or more attendees.
Request:
POST https://api.truto.one/unified/calendar/availability?integrated_account_id=acc_abc123
Content-Type: application/json
Authorization: Bearer YOUR_TRUTO_API_KEY
{
"start_time": "2026-10-15T09:00:00Z",
"end_time": "2026-10-15T17:00:00Z",
"timezone": "America/Los_Angeles",
"attendees": [
"alice@acme.com",
"bob@acme.com"
]
}Response:
{
"result": [
{
"attendee": "alice@acme.com",
"busy": [
{ "start": "2026-10-15T10:00:00Z", "end": "2026-10-15T11:00:00Z" },
{ "start": "2026-10-15T14:30:00Z", "end": "2026-10-15T15:00:00Z" }
]
}
]
}Your application logic compares these intervals against the requested window and proposes free slots. The shape is identical whether the underlying provider is Google Calendar's freeBusy.query or Microsoft Graph's getSchedule.
Step 4: Creating an Event
Once you have identified a free time slot, you can create the calendar event. The unified schema requires you to pass the start time, end time, and an array of contacts (attendees).
Request:
POST https://api.truto.one/unified/calendar/events?integrated_account_id=acc_abc123
Content-Type: application/json
Authorization: Bearer YOUR_TRUTO_API_KEY
{
"calendar_id": "primary",
"title": "Q4 Roadmap Review",
"description": "Reviewing the upcoming integration pipeline.",
"start_time": "2026-10-15T16:00:00Z",
"end_time": "2026-10-15T16:30:00Z",
"timezone": "America/Los_Angeles",
"attendees": [
{
"email": "alice@acme.com",
"name": "Alice",
"status": "needs_action"
}
],
"conference": { "provider": "google_meet" }
}Response:
{
"result": {
"id": "provider-specific-event-id-9876",
"title": "Q4 Roadmap Review",
"status": "confirmed",
"html_link": "https://calendar.google.com/calendar/event?eid=...",
"created_at": "2026-10-10T14:22:00Z"
}
}The conference field is auto-translated: Google creates a Meet link, Outlook creates a Teams link, and others fall back to whatever they natively support. If the provider cannot honor a field, you get a structured error—not a silent drop.
Step 5: Subscribe to Webhooks (Optional)
For real-time updates, register a webhook subscription against the events resource. Truto handles the upstream subscription lifecycle (Microsoft's three-day renewal, Google's channel expiry) and delivers normalized record:* events to your endpoint with an HMAC signature. The Link UI + Unified Webhooks quickstart covers the signature verification pattern in detail.
By documenting your API in this exact format, you provide a clear, linear path to value. Developers do not have to guess which fields are required or how to handle provider-specific nuances. Five HTTP calls. Same shape across every provider.
AI Agent Use Cases: Orchestrating Meetings via MCP
The Model Context Protocol (MCP) is a standardized interface that allows AI models to securely interact with external tools and data sources.
Large Language Models (LLMs) struggle to interact with raw third-party APIs because vendor documentation is often unstructured, and endpoints vary wildly between providers. A unified calendar API solves this by providing a single, highly structured JSON schema that an LLM can easily understand and generate payloads for.
Truto auto-generates an MCP server from the integration config, so an agent in Claude, ChatGPT, or a LangGraph workflow gets typed tool definitions for every calendar operation without you writing manual tool wrappers. (For a deep dive into a specific provider, see our guide on connecting Cal.com to AI agents). When you expose a unified calendar API to an AI agent via MCP, you unlock entirely new autonomous workflows:
1. Autonomous Meeting Orchestration
An AI agent receives an email request from a prospect asking for a demo. The agent uses the availability endpoint to find open slots for the internal sales team. It replies to the prospect with three options. Upon confirmation, the agent uses the events.create endpoint to secure the time on the sales rep's calendar and invite the external Contacts. This entirely removes the human from the scheduling ping-pong, running the whole loop against the unified API with no provider-specific branching.
2. Pre-Meeting Context Briefings (RAG)
A scheduled cron job triggers a background agent 15 minutes before an Event begins. The agent fetches the Event details, downloads any attached agenda documents via the Attachments endpoint, and cross-references the external Contacts against a Unified CRM API. The agent then synthesizes a comprehensive briefing document and posts it directly into Slack via a Unified Instant Messaging API. Same pattern, three different unified APIs, zero glue code per provider. The user walks into the meeting fully briefed without lifting a finger.
3. Smart Time-Blocking
An agent continuously monitors a user's ticketing backlog in a project management system. When a high-priority ticket lands, it queries the user's Availability and automatically creates a "Deep Work" Event on their primary calendar to ensure complex engineering tasks have dedicated focus time. Because the calendar action is one MCP tool call, the agent's planning logic stays simple.
One honest caveat for agent workloads: AI agents can generate request patterns that look nothing like human traffic. Bursty bulk reads, unbounded loops, and accidental retries are common. Because Truto passes 429s through, you need explicit rate-limit handling in your agent's tool-call loop—not just assuming "the platform will figure it out." Budget for this in the design phase.
Strategic Next Steps
The entire point of a unified calendar API is to compress a quarter of integration work into a single sprint. Shipping a calendar integration should not dictate your entire quarterly roadmap. By leveraging a unified API architecture, you bypass the massive capital expense of building custom OAuth flows, normalizing recurrence logic, and maintaining provider-specific state machines.
The trade-offs are real—you accept a schema that is slightly less expressive than each provider's native API (a challenge we explore in our piece on the hidden cost of rigid schemas), and you take ownership of rate-limit retry policies on the client side—but for the overwhelming majority of B2B SaaS calendar workloads, those are excellent trades. Your engineering team's responsibility shifts from writing integration boilerplate to simply handling standardized rate limit headers and executing your core business logic.
A reasonable next-step checklist:
- Pick the first two providers your enterprise pipeline actually requires (almost always Google Calendar and Microsoft Outlook).
- Build the happy-path flow above as a thin internal prototype—list calendars, query availability, create an event, subscribe to webhooks.
- Define your client-side rate-limit policy before you scale traffic. The IETF headers tell you everything you need.
- Decide on cached vs. live reads based on your workload. Polling availability for thousands of users? Use synced data. Booking flows? Stay live.
- If AI agents are on the roadmap, wire the MCP server in from day one rather than retrofitting it later.
FAQ
- What is a unified calendar API and why do B2B SaaS teams use one?
- A unified calendar API exposes a single schema and set of endpoints that work across Google Calendar, Microsoft Outlook, Calendly, and other providers. B2B SaaS teams use one to avoid building and maintaining separate native integrations, which typically cost $15,000 to $80,000 each plus 15-25% in annual maintenance.
- How does a unified calendar API handle rate limits?
- A pass-through unified API will not silently absorb rate limits. It passes upstream HTTP 429 errors directly to the caller, normalizing the rate limit metadata into IETF-standard headers (ratelimit-limit, ratelimit-remaining, ratelimit-reset). The caller is responsible for implementing exponential backoff logic.
- Can AI agents use the Unified Calendar API via MCP?
- Yes. A Model Context Protocol (MCP) server can be auto-generated from the unified API configuration, allowing agents in Claude, ChatGPT, or LangGraph to autonomously check availability, book meetings, and generate pre-meeting RAG briefings without manual tool-wrapper code.
- What is schema normalization in calendar APIs?
- Schema normalization is the process of translating disparate third-party data structures (like Google Calendar events and Microsoft Graph schedules) into a single, predictable JSON format, ensuring your application always receives fields like start_time and attendees in the exact same shape.
- Does the unified API store my users' calendar event data?
- By default, the unified API operates in a real-time pass-through mode. Requests are proxied to the upstream provider and responses are normalized and returned to the caller without persisting event payloads. Optional synced data storage is available for read-heavy workloads.