# Email, calendar & files

Read and send email, manage calendar events and work with files in your users' own Google and Microsoft accounts through one API.

Connect a user's Google or Microsoft account and you can work in their own mailbox, calendar and drive with your Pozy key. Send a follow-up from their Gmail, book a meeting in their Outlook calendar, save a report to their OneDrive. The endpoints are the same for both providers: every object carries `provider` (`google` or `microsoft`) and `accountId`, so one integration covers both.

## What you can do

| Area | Google | Microsoft | Guide |
| --- | --- | --- | --- |
| Email: list, search, read, send, reply, label or flag, move, trash, attachments | Gmail | Outlook mail | [Email](https://pozy.ai/docs/productivity/email) |
| Calendar: events, invitations, RSVP, free-busy, meeting slots | Google Calendar with Meet | Outlook Calendar with Teams | [Calendar](https://pozy.ai/docs/productivity/calendar) |
| Files: list, search, upload, download, folders, share links | Google Drive (picked or created files only) | OneDrive (every file the user can reach) | [Files](https://pozy.ai/docs/productivity/files) |
| Contacts: read-only sync into `/v1/contacts` | Google Contacts | Outlook contacts | [Contacts](https://pozy.ai/docs/inbox/contacts) |

Incoming mail also lands in the [inbox](https://pozy.ai/docs/inbox) as conversations, one per thread, so the same inbox that handles DMs and comments can handle email.

## Connect an account

Pass the areas you need in `scopes` when you request the connect link. One account is one mailbox, and you can add areas later without changing the account id.

```bash cURL
curl "https://api.pozy.ai/v1/connect/google?profileId=6710c3a9e4b0d2f1a8c95e21&scopes=email,calendar,files&redirect_url=https://app.example.com/connected" \
  -H "Authorization: Bearer $POZY_API_KEY"
```
```ts Node
const res = await fetch("https://api.pozy.ai/v1/connect/microsoft?profileId=6710c3a9e4b0d2f1a8c95e21&scopes=email,calendar&redirect_url=https:%2F%2Fapp.example.com%2Fconnected", {
  headers: { Authorization: `Bearer ${process.env.POZY_API_KEY}` },
});
const data = await res.json();
if (!res.ok) throw new Error(data.error);
```
```python Python
import os, requests

resp = requests.get(
    "https://api.pozy.ai/v1/connect/google",
    headers={"Authorization": f"Bearer {os.environ['POZY_API_KEY']}"},
    params={"profileId": "6710c3a9e4b0d2f1a8c95e21", "scopes": "email,calendar,files", "redirect_url": "https://app.example.com/connected"},
)
```

| `scopes` value | Unlocks |
| --- | --- |
| `email` | The Email endpoints and email in the inbox |
| `calendar` | The Calendar endpoints |
| `files` | The Files endpoints |
| `contacts` | A read-only daily contacts sync |

A call that needs an area the account was not granted returns `412 account_scope_missing`, with `grantedAreas` and `missingArea` in `details`. Reconnect with the area added. Provider specifics (Gmail send caps, Drive's file grants, Microsoft admin consent) are on the [Google Workspace](https://pozy.ai/docs/platforms/google) and [Microsoft 365](https://pozy.ai/docs/platforms/microsoft) pages.

## Find the accounts

`GET /v1/accounts?platform=google` and `GET /v1/accounts?platform=microsoft` list connected mailboxes. Every call in this section takes the mailbox's `accountId`: in the query on reads, in the body on writes.

## Shared rules

| Topic | Rule |
| --- | --- |
| Ids | The provider's own message, thread, event and file ids |
| Times | ISO 8601 with an offset |
| Pagination | `limit` and `cursor`; responses return `pagination.hasMore` and `pagination.nextCursor` |
| Reads | Live calls to the provider, not billed per call, counted against your [rate limit](https://pozy.ai/docs/getting-started/rate-limits) |
| Provider throttling | `429 rate_limited` with `Retry-After` |
| Lost access | `401 reconnect_required`. When the provider refuses to renew access, the account is marked disconnected and `account.disconnected` fires |

## Stay in sync with webhooks

When an account connects, Pozy subscribes to the provider's push notifications for the granted areas and renews them for you. Subscribe your [webhook endpoint](https://pozy.ai/docs/webhooks) to the events you care about. Calendar, file and contact events carry the changed object's `id` and `changeType`: fetch it to read its current state.

| Event | When it fires |
| --- | --- |
| [`account.rate_limited`](https://pozy.ai/docs/webhooks/events#account-rate-limited) | Mailbox sending cooldown started. |
| [`calendar.event.created`](https://pozy.ai/docs/webhooks/events#calendar-event-created) | Calendar event created. |
| [`calendar.event.updated`](https://pozy.ai/docs/webhooks/events#calendar-event-updated) | Calendar event updated. |
| [`calendar.event.deleted`](https://pozy.ai/docs/webhooks/events#calendar-event-deleted) | Calendar event deleted. |
| [`file.created`](https://pozy.ai/docs/webhooks/events#file-created) | File created. |
| [`file.updated`](https://pozy.ai/docs/webhooks/events#file-updated) | File updated. |
| [`file.picked`](https://pozy.ai/docs/webhooks/events#file-picked) | Files picked. |
| [`file.deleted`](https://pozy.ai/docs/webhooks/events#file-deleted) | File deleted. |
| [`contact.updated`](https://pozy.ai/docs/webhooks/events#contact-updated) | Contact updated. |
| [`contact.deleted`](https://pozy.ai/docs/webhooks/events#contact-deleted) | Contact deleted. |

New mail arrives as the inbox events `message.received`, `message.sent` and `conversation.started`. See [Inbox](https://pozy.ai/docs/inbox/messages).

## Health

`GET /v1/accounts/{accountId}/health` reports the mailbox's daily send allowance as `sendCap` (`limit`, `used`, `resetsAt`) and the push subscription state as `push` (`active`, `pending`, `failed` or `not_applicable`).

## Endpoints

| Endpoint | What it does |
| --- | --- |
| [`GET /v1/calendar/calendars`](https://pozy.ai/docs/api/listCalendars) | List calendars |
| [`GET /v1/calendar/events`](https://pozy.ai/docs/api/listCalendarEvents) | List events in a window |
| [`POST /v1/calendar/events`](https://pozy.ai/docs/api/createCalendarEvent) | Create an event |
| [`GET /v1/calendar/events/{eventId}`](https://pozy.ai/docs/api/getCalendarEvent) | Get an event |
| [`PATCH /v1/calendar/events/{eventId}`](https://pozy.ai/docs/api/updateCalendarEvent) | Update an event |
| [`DELETE /v1/calendar/events/{eventId}`](https://pozy.ai/docs/api/deleteCalendarEvent) | Delete an event |
| [`POST /v1/calendar/events/{eventId}/rsvp`](https://pozy.ai/docs/api/rsvpCalendarEvent) | Respond to an invitation |
| [`POST /v1/calendar/free-busy`](https://pozy.ai/docs/api/calendarFreeBusy) | Busy blocks for one or more accounts |
| [`POST /v1/calendar/availability`](https://pozy.ai/docs/api/calendarAvailability) | Find meeting slots across accounts |
| [`GET /v1/email/threads`](https://pozy.ai/docs/api/listEmailThreads) | List email threads |
| [`GET /v1/email/threads/{threadId}`](https://pozy.ai/docs/api/getEmailThread) | Get an email thread with its messages |
| [`PATCH /v1/email/threads/{threadId}`](https://pozy.ai/docs/api/updateEmailThread) | Update every message in a thread |
| [`GET /v1/email/messages`](https://pozy.ai/docs/api/listEmailMessages) | List email messages |
| [`POST /v1/email/messages`](https://pozy.ai/docs/api/sendEmailMessage) | Send an email |
| [`GET /v1/email/messages/{messageId}`](https://pozy.ai/docs/api/getEmailMessage) | Get an email message |
| [`PATCH /v1/email/messages/{messageId}`](https://pozy.ai/docs/api/updateEmailMessage) | Mark read or starred, or move a message |
| [`DELETE /v1/email/messages/{messageId}`](https://pozy.ai/docs/api/trashEmailMessage) | Move a message to trash |
| [`POST /v1/email/messages/{messageId}/reply`](https://pozy.ai/docs/api/replyEmailMessage) | Reply to a message |
| [`GET /v1/email/folders`](https://pozy.ai/docs/api/listEmailFolders) | List mailbox folders |
| [`GET /v1/email/attachments/{attachmentId}`](https://pozy.ai/docs/api/downloadEmailAttachment) | Download an attachment |
| [`GET /v1/files`](https://pozy.ai/docs/api/listFiles) | List files in a folder or search the drive |
| [`POST /v1/files`](https://pozy.ai/docs/api/uploadFile) | Upload a file |
| [`POST /v1/files/folders`](https://pozy.ai/docs/api/createFolder) | Create a folder |
| [`POST /v1/files/picker-sessions`](https://pozy.ai/docs/api/createFilePickerSession) | Create a hosted Google Picker session (not available yet) |
| [`GET /v1/files/{fileId}`](https://pozy.ai/docs/api/getFile) | Get a file or folder |
| [`PATCH /v1/files/{fileId}`](https://pozy.ai/docs/api/updateFile) | Rename or move a file |
| [`DELETE /v1/files/{fileId}`](https://pozy.ai/docs/api/trashFile) | Move a file to the trash |
| [`GET /v1/files/{fileId}/download`](https://pozy.ai/docs/api/downloadFile) | Download a file |
| [`GET /v1/files/{fileId}/share-link`](https://pozy.ai/docs/api/getFileShareLink) | Get an anyone-with-the-link share link |
