# Outlook Calendar API vs Graph

Source: https://developer.nylas.com/docs/cookbook/calendar/outlook-vs-graph-calendar/

You searched for the "Outlook Calendar API" and landed on Microsoft Graph docs, which talk about `/me/events` and Azure app registrations. That confusion is the whole problem: the standalone Outlook REST calendar API was retired, and reading an Outlook calendar now means learning Graph, its consent model, and its throttling rules before you fetch a single event.

This guide untangles the naming, shows how to read Outlook and Microsoft 365 events through one unified endpoint, and is honest about when calling Graph yourself is the better call.

## What is the difference between the Outlook calendar API and the Microsoft Graph?

There is no separate Outlook calendar API anymore. Microsoft retired the standalone Outlook REST API and folded calendar access into Microsoft Graph. When people say "Outlook Calendar API" today, they mean the Graph calendar endpoints, like `GET /me/events` and `GET /me/calendars`, served from `https://graph.microsoft.com/v1.0`.

So "Outlook Calendar API" and "Microsoft Graph calendar API" point at the same surface. The old `outlook.office.com/api` host issued a deprecation notice and stopped serving new tenants, which is why tutorials referencing it break. Graph is the single gateway for Microsoft 365, Outlook.com, and Exchange Online calendars. Every event read, every recurrence expansion, and every Teams join link now flows through one host with one OAuth model that an Entra administrator controls.

## How do I read Outlook calendar events through a unified endpoint?

Send one `GET` to `/v3/grants/{grant_id}/events` with a `calendar_id` query parameter, and you get Outlook events back without touching Graph directly. The `grant_id` replaces the Azure app registration and the per-mailbox Graph token. The same call reads Google and iCloud calendars, so you maintain one parser instead of mapping Graph's `event` resource by hand.

The request below lists events from a connected Microsoft account. The `calendar_id` parameter is required, and `primary` targets the account's default calendar. The endpoint returns up to 50 events per page by default in a schema shared across every provider, including a `when` object, `participants`, and a `conferencing` block when the organizer added Teams.

```bash
curl --request GET \
  --url 'https://api.us.nylas.com/v3/grants/<NYLAS_GRANT_ID>/events?calendar_id=primary&limit=50' \
  --header 'Authorization: Bearer <NYLAS_API_KEY>'
```

```python [outlookGraphCal-Python SDK]
from nylas import Client

nylas = Client(api_key="<NYLAS_API_KEY>")

events = nylas.events.list(
    "<NYLAS_GRANT_ID>",
    query_params={"calendar_id": "primary", "limit": 50},
)

for event in events.data:
    print(event.title, event.when)
```

For the full filter and pagination flow on Microsoft accounts, see [list Microsoft calendar events](/docs/cookbook/calendar/events/list-events-microsoft/).

## How do I use the Microsoft Graph calendar API to read events in C#?

To read events with Graph in C#, install the `Microsoft.Graph` SDK, authenticate through MSAL with a `Calendars.Read` scope, then call `graphClient.Me.Events.GetAsync()`. The SDK handles the `GET /me/events` request and token refresh, but you still register an Azure app, configure admin consent, and map Windows timezone IDs like "Eastern Standard Time" to IANA yourself.

That C# path works, and Microsoft maintains the SDK well. The cost shows up around it: MSAL token lifecycle, Entra app permissions, and Graph's throttling. If you'd rather skip the Azure setup, the unified endpoint above returns the same Outlook events as plain JSON over HTTP, callable from any language with a single bearer token. You write a `HttpClient.GetAsync` against `/v3/grants/{grant_id}/events` and parse a provider-neutral response. For the C# Graph reference itself, see Microsoft's [calendar events documentation](https://learn.microsoft.com/en-us/graph/api/user-list-events).

## Which calendar API supports both Google Calendar and Outlook Calendar?

A unified calendar API reads both Google Calendar and Outlook through one schema and one OAuth flow. The endpoint `GET /v3/grants/{grant_id}/events?calendar_id=<CALENDAR_ID>` returns the same JSON shape whether the underlying account is Google, Microsoft 365, Outlook.com, or iCloud, so a single code path covers every supported calendar provider instead of two separate integrations.

Microsoft Graph reads Outlook only. Supporting Google alongside it means a second, unrelated build against the Google Calendar API, with its own OAuth project, ID formats, and quotas. The unified layer collapses that into one grant model, and adding iCloud or Exchange later costs no new integration. The table below compares the work each approach actually requires for a cross-provider calendar feature.

| Task | Microsoft Graph directly | **Unified calendar API** |
| --- | --- | --- |
| **Auth setup** | Azure app registration plus admin consent per tenant | **1 connector, OAuth handled for you** |
| **Read Outlook events** | `GET /me/events` with `Calendars.Read` | **`GET /v3/grants/{grant_id}/events?calendar_id=`** |
| **Read Google events** | Separate Google Calendar API build | **Same endpoint, same parser** |
| **Timezones** | Map Windows IDs to IANA in your code | **Normalized to IANA automatically** |
| **Provider coverage** | Microsoft only | **Google, Microsoft, iCloud, EWS** |

## How does Graph throttling affect Outlook calendar reads?

Graph throttles Outlook calendar requests at the mailbox level, and hitting the ceiling returns a `429 Too Many Requests` with a `Retry-After` header you must honor. Outlook applies aggressive per-app, per-mailbox throttling on top of a service-wide cap. Polling a busy calendar burns through that budget fast.

The fix is to stop polling. When you read Outlook events through the unified endpoint and a `429` comes back from Graph, the API retries with backoff for you, so your code doesn't carry retry logic. For change awareness, one webhook subscription replaces a polling loop and never expires the way Graph's per-resource subscriptions do, which renew roughly every 3 days. To list a non-default calendar's ID before reading its events, call `GET /v3/grants/{grant_id}/calendars` once and store the returned ID. Microsoft's own [throttling limits](https://learn.microsoft.com/en-us/graph/throttling-limits) documentation lists the per-service caps.

## When should you use Microsoft Graph directly?

Use Graph directly when your app is Microsoft-only and reaches past calendar into services no other API exposes. Graph is the single gateway to Teams messages, SharePoint, OneDrive, Planner, and Entra directory data. If your roadmap stays inside Microsoft 365 and touches those surfaces, the Azure registration pays for itself, and a unified layer would add a hop you don't need.

Two things change the answer here: adding Google, or needing nothing beyond calendar. Supporting two providers through Graph plus the Google Calendar API means two OAuth projects, two ID formats, and two throttling models to babysit. One schema across both is fewer moving parts and fewer places to break. If you connect on-premises Exchange too, the protocol split matters: see [EWS vs Microsoft Graph for email](/docs/cookbook/email/ews-vs-microsoft-graph/) for how older Exchange servers fit in alongside Graph-era Microsoft 365.

## What's next

- [List Microsoft calendar events](/docs/cookbook/calendar/events/list-events-microsoft/) for filters, recurring events, and Teams data on Outlook accounts
- [EWS vs Microsoft Graph for email](/docs/cookbook/email/ews-vs-microsoft-graph/) for the on-premises Exchange versus Microsoft 365 split
- [Manage calendars](/docs/cookbook/calendar/manage-calendars/) to list calendar IDs across Google, Outlook, and iCloud
- [Getting started with Nylas](/docs/v3/getting-started/) to create a project, connector, and your first grant