> ## Documentation Index
> Fetch the complete documentation index at: https://major-5cc5eebc-docs-bot-mr2qm9w6-typctx.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Google Calendar

> List, search, and create calendar events.

The Google Calendar connector lets you interact with Google Calendar. It uses OAuth for authentication, so you connect your Google account once and Major handles token management.

For full API details, see the [Google Calendar API documentation](https://developers.google.com/calendar/api/guides/overview).

## Setup

1. Go to **Organization Settings > Connectors**
2. Click **Add Connector** and select **Google Calendar**
3. Choose the access scope:
   * **Read only** — Can list and read calendar events
   * **Read and write** — Can list, read, and create calendar events
4. Choose the authentication mode:
   * **Shared** — Use a single shared account (the person configuring the resource provides credentials)
   * **Per-user** — Each app user connects their own account
5. Click **Connect to Google** to authorize access
6. Select the calendar you want to connect (or skip if using per-user auth — users will select their own)

Attach the resource to your app via `major resource manage` (CLI) or the web editor. Major generates a client in `src/clients/`.

## Per-User Authentication

When you configure a Google Calendar resource for **per-user** authentication, end-users authenticate with their own Google accounts instead of using shared credentials.

### User Flow

1. User accesses a deployed app that uses a per-user Google Calendar resource
2. If they haven't connected their account, Major redirects them to the `/connect` page
3. User clicks **Connect Google Calendar** and authorizes access to their own calendar
4. User is returned to the app and can now use Google Calendar features

### Managing Connections

Users can view and manage their connected OAuth accounts by clicking their profile photo in the bottom left and selecting **Connected Accounts**. From there, they can disconnect individual OAuth credentials or reconnect if access expires.

Once disconnected, users must re-authorize via the `/connect` page if they want to use apps that require that connection.

## Usage

Import the generated client and use the helper methods:

```typescript theme={null}
import { googlecalendarClient } from './clients';
```

### Listing calendars

```typescript theme={null}
const result = await googlecalendarClient.googlecalendar_list_calendars(
  'list-calendars'
);

if (result.ok) {
  const calendars = result.result.items;
  calendars.forEach(cal => {
    console.log(cal.id, cal.summary);
  });
}
```

**Parameters:**

* `operationName` — A name for logging and debugging

**Returns:**

* `items` — Array of calendar objects with `id`, `summary`, `description`, and other metadata

### Listing events

```typescript theme={null}
const result = await googlecalendarClient.googlecalendar_list_events(
  'list-events',
  {
    calendarId: 'primary',
    maxResults: 10,
    orderBy: 'startTime',
    singleEvents: true,
    timeMin: '2024-01-01T00:00:00Z',
    timeMax: '2024-12-31T23:59:59Z'
  }
);

if (result.ok) {
  const events = result.result.items;
  events.forEach(event => {
    console.log(event.summary, event.start.dateTime);
  });
}
```

**Parameters:**

* `operationName` — A name for logging and debugging
* `options` — Query options:
  * `calendarId` — Calendar identifier (default: `primary`)
  * `maxResults` — Maximum events to return (1–250)
  * `orderBy` — Sort order: `startTime` or `updated`
  * `singleEvents` — Expand recurring events into instances (default: `false`)
  * `timeMin` — Lower bound (RFC 3339 format)
  * `timeMax` — Upper bound (RFC 3339 format)
  * `q` — Search query term

**Returns:**

* `items` — Array of event objects with `id`, `summary`, `start`, `end`, and other metadata

### Creating events

```typescript theme={null}
const result = await googlecalendarClient.googlecalendar_create_event(
  'create-event',
  {
    calendarId: 'primary',
    summary: 'Team Meeting',
    description: 'Quarterly planning session',
    start: {
      dateTime: '2024-02-15T14:00:00',
      timeZone: 'America/New_York'
    },
    end: {
      dateTime: '2024-02-15T15:00:00',
      timeZone: 'America/New_York'
    },
    attendees: [
      { email: 'alice@example.com' },
      { email: 'bob@example.com' }
    ]
  }
);

if (result.ok) {
  console.log('Event created:', result.result.id);
}
```

**Parameters:**

* `operationName` — A name for logging and debugging
* `eventBody` — Event object with:
  * `summary` — Event title (required)
  * `description` — Event description
  * `start` — Start time with `dateTime` and optional `timeZone`
  * `end` — End time with `dateTime` and optional `timeZone`
  * `attendees` — Array of attendee objects with `email`
  * `location` — Event location
  * `recurrence` — Recurrence rules (RFC 5545 format)

**Returns:**

* `id` — The created event's ID
* `htmlLink` — Link to the event in Google Calendar
* Full event object with all details

## Low-level API

For operations not covered by helper methods, use `invoke()` directly:

```typescript theme={null}
const result = await googlecalendarClient.googlecalendar_invoke(
  'GET',
  '/calendars/primary/events',
  'list-events',
  {
    query: { maxResults: 10 }
  }
);
```

### Supported API paths

| Method | Path                                       | Description       |
| ------ | ------------------------------------------ | ----------------- |
| GET    | `/users/me/calendarList`                   | List calendars    |
| GET    | `/calendars/{calendarId}/events`           | List events       |
| POST   | `/calendars/{calendarId}/events`           | Create event      |
| GET    | `/calendars/{calendarId}/events/{eventId}` | Get event details |
| PUT    | `/calendars/{calendarId}/events/{eventId}` | Update event      |
| DELETE | `/calendars/{calendarId}/events/{eventId}` | Delete event      |

<Note>
  The calendar ID is configured in the resource and does not need to be included in all API paths, though you can specify a different calendar by passing `calendarId` in options or the URL.
</Note>

## Error handling

```typescript theme={null}
import { ResourceInvokeError } from '@major-tech/resource-client';

try {
  const result = await googlecalendarClient.googlecalendar_list_events(
    'list-events',
    { calendarId: 'primary' }
  );

  if (!result.ok) {
    // Resource returned an error (e.g., calendar not found)
    console.error('Calendar error:', result.error.message);
    return;
  }

  // Success
  console.log(result.result.items);

} catch (e) {
  if (e instanceof ResourceInvokeError) {
    // Client-level error (e.g., OAuth not completed)
    console.error('Invocation error:', e.message);
  }
}
```

### Common errors

| Error            | Cause                                      |
| ---------------- | ------------------------------------------ |
| 401 Unauthorized | OAuth not completed—reconnect the resource |
| 403 Forbidden    | Write operation on a read-only resource    |
| 404 Not Found    | Calendar or event not found                |
| 400 Bad Request  | Invalid event data or query parameters     |

## Scope and permissions

When creating the resource, you choose between:

* **Read only** — `GET` requests only
* **Read and write** — Full read/write access including event creation and deletion

The scope is enforced at the API level. If you try to create an event with a read-only resource, you'll get a 403 error.

<Tip>
  Major uses the most restrictive Google OAuth scope, which only grants access to the specific calendar you selected—not your entire Google Calendar.
</Tip>
