介绍
# Zoho Calendar
使用托管的 OAuth 身份验证访问 Zoho Calendar API。管理日历和事件,支持包括循环事件和参会者管理在内的完整 CRUD 操作。
## Quick Start
```bash # List calendars python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/zoho-calendar/api/v1/calendars') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
## Base URL
``` https://gateway.maton.ai/zoho-calendar/api/v1/{endpoint} ```
网关将请求代理到 `calendar.zoho.com/api/v1` 并自动注入您的 OAuth 令牌。
## Authentication
所有请求都需要在 Authorization 头中包含 Maton API 密钥:
``` Authorization: Bearer $MATON_API_KEY ```
**Environment Variable:** 将您的 API 密钥设置为 `MATON_API_KEY`:
```bash export MATON_API_KEY="YOUR_API_KEY" ```
### Getting Your API Key
1. 在 [maton.ai](https://maton.ai) 登录或创建账户 2. 前往 [maton.ai/settings](https://maton.ai/settings) 3. 复制您的 API 密钥
## Connection Management
在 `https://ctrl.maton.ai` 管理您的 Zoho Calendar OAuth 连接。
### List Connections
```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections?app=zoho-calendar&status=ACTIVE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
### Create Connection
```bash python <<'EOF' import urllib.request, os, json data = json.dumps({'app': 'zoho-calendar'}).encode() req = urllib.request.Request('https://ctrl.maton.ai/connections', data=data, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Content-Type', 'application/json') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
### Get Connection
```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
**Response:** ```json { "connection": { "connection_id": "21fd90f9-5935-43cd-b6c8-bde9d915ca80", "status": "ACTIVE", "creation_time": "2025-12-08T07:20:53.488460Z", "last_updated_time": "2026-01-31T20:03:32.593153Z", "url": "https://connect.maton.ai/?session_token=...", "app": "zoho-calendar", "metadata": {} } } ```
在浏览器中打开返回的 `url` 以完成 OAuth 授权。
### Delete Connection
```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections/{connection_id}', method='DELETE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
### Specifying Connection
如果您有多个 Zoho Calendar 连接,请使用 `Maton-Connection` 头指定要使用的连接:
```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/zoho-calendar/api/v1/calendars') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('Maton-Connection', '21fd90f9-5935-43cd-b6c8-bde9d915ca80') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
如果省略,网关将使用默认(最旧的)活动连接。
## API Reference
### Calendars
#### List Calendars
```bash GET /zoho-calendar/api/v1/calendars ```
**Example:**
```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/zoho-calendar/api/v1/calendars') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
**Response:** ```json { "calendars": [ { "uid": "fda9b0b4ad834257b622cb3dc3555727", "name": "My Calendar", "color": "#8cbf40", "textcolor": "#FFFFFF", "timezone": "PST", "isdefault": true, "category": "own", "privilege": "owner" } ] } ```
#### Get Calendar Details
```bash GET /zoho-calendar/api/v1/calendars/{calendar_uid} ```
**Example:**
```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/zoho-calendar/api/v1/calendars/fda9b0b4ad834257b622cb3dc3555727') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
#### Create Calendar
```bash POST /zoho-calendar/api/v1/calendars?calendarData={json} ```
**Required Fields:** - `name` - 日历名称(最多 50 个字符) - `color` - 十六进制颜色代码(例如 `#FF5733`)
**Optional Fields:** - `textcolor` - 文本颜色十六进制代码 - `description` - 日历描述(最多 1000 个字符) - `timezone` - 日历时区 - `include_infreebusy` - 显示为“忙碌”/“空闲”(布尔值) - `public` - 可见性级别(`disable`、`freebusy` 或 `view`)
**Example:**
```bash python <<'EOF' import urllib.request, os, json, urllib.parse
calendarData = { "name": "Work Calendar", "color": "#FF5733", "textcolor": "#FFFFFF", "description": "My work calendar" }
url = f'https://gateway.maton.ai/zoho-calendar/api/v1/calendars?calendarData={urllib.parse.quote(json.dumps(calendarData))}' req = urllib.request.Request(url, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
**Response:** ```json { "calendars": [ { "uid": "86fb9745076e4672ae4324f05e1f5393", "name": "Work Calendar", "color": "#FF5733", "textcolor": "#FFFFFF" } ] } ```
#### Delete Calendar
```bash DELETE /zoho-calendar/api/v1/calendars/{calendar_uid} ```
**Example:**
```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/zoho-calendar/api/v1/calendars/86fb9745076e4672ae4324f05e1f5393', method='DELETE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
**Response:** ```json { "calendars": [ { "uid": "86fb9745076e4672ae4324f05e1f5393", "calstatus": "deleted" } ] } ```
### Events
#### List Events
```bash GET /zoho-calendar/api/v1/calendars/{calendar_uid}/events?range={json} ```
**Query Parameters:**
| Parameter | Type | Description | |-----------|------|-------------| | `range` | JSON object | **必需。** 格式为 `{"start":"yyyyMMdd","end":"yyyyMMdd"}` 的开始和结束日期。最大跨度为 31 天。 | | `byinstance` | boolean | 如果为 true,循环事件实例将单独返回 | | `timezone` | string | 日期时间值的时区 |
**Example:**
```bash python <<'EOF' import urllib.request, os, json, urllib.parse from datetime import datetime, timedelta
today = datetime.now() end_date = today + timedelta(days=7) range_param = json.dumps({ "start": today.strftime("%Y%m%d"), "end": end_date.strftime("%Y%m%d") })
url = f'https://gateway.maton.ai/zoho-calendar/api/v1/calendars/fda9b0b4ad834257b622cb3dc3555727/events?range={urllib.parse.quote(range_param)}' req = urllib.request.Request(url) req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
**Response:** ```json { "events": [ { "uid": "[email protected]", "title": "Team Meeting", "dateandtime": { "timezone": "America/Los_Angeles", "start": "20260206T100000-0800", "end": "20260206T110000-0800" }, "isallday": false, "etag": "1770368451507", "organizer": "[email protected]" } ] } ```
#### Get Event Details
```bash GET /zoho-calendar/api/v1/calendars/{calendar_uid}/events/{event_uid} ```
**Example:**
```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://gateway.maton.ai/zoho-calendar/api/v1/calendars/fda9b0b4ad834257b622cb3dc3555727/events/[email protected]') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
#### Create Event
```bash POST /zoho-calendar/api/v1/calendars/{calendar_uid}/events?eventdata={json} ```
**Required Fields (in eventdata):** - `dateandtime` - 包含 `start`、`end` 以及可选 `timezone` 的对象 - 格式:对于定时事件为 `yyyyMMdd'T'HHmmss'Z'` (GMT) - 格式:对于全天事件为 `yyyyMMdd`
**Optional Fields:** - `title` - 事件名称 - `description` - 事件详情(最多 10,000 个字符) - `location` - 事件位置(最多 255 个字符) - `isallday` - 全天事件的布尔值 - `isprivate` - 向非代理人隐藏详情的布尔值 - `color` - 十六进制颜色代码 - `attendees` - 参会者对象数组 - `reminders` - 提醒对象数组 - `rrule` - 循环规则字符串(例如 `FREQ=DAILY;COUNT=5`)
**Example:**
```bash python <<'EOF' import urllib.request, os, json, urllib.parse from datetime import datetime, timedelta
start_time = datetime.utcnow() + timedelta(hours=1) end_time = start_time + timedelta(hours=1)
eventdata = { "title": "Team Meeting", "dateandtime": { "timezone": "America/Los_Angeles", "start": start_time.strftime("%Y%m%dT%H%M%SZ"), "end": end_time.strftime("%Y%m%dT%H%M%SZ") }, "description": "Weekly team sync", "location": "Conference Room A" }
url = f'https://gateway.maton.ai/zoho-calendar/api/v1/calendars/fda9b0b4ad834257b622cb3dc3555727/events?eventdata={urllib.parse.quote(json.dumps(eventdata))}' req = urllib.request.Request(url, method='POST') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
**Response:** ```json { "events": [ { "uid": "[email protected]", "title": "Team Meeting", "dateandtime": { "timezone": "America/Los_Angeles", "start": "20260206T100000-0800", "end": "20260206T110000-0800" }, "etag": "1770368451507", "estatus": "added" } ] } ```
#### Update Event
```bash PUT /zoho-calendar/api/v1/calendars/{calendar_uid}/events/{event_uid}?eventdata={json} ```
**Required Fields:** - `dateandtime` - 开始和结束时间 - `etag` - 当前 etag 值(来自 Get Event Details)
**Optional Fields:** 与 Create Event 相同
**Example:**
```bash python <<'EOF' import urllib.request, os, json, urllib.parse from datetime import datetime, timedelta
start_time = datetime.utcnow() + timedelta(hours=2) end_time = start_time + timedelta(hours=1)
eventdata = { "title": "Updated Team Meeting", "dateandtime": { "timezone": "America/Los_Angeles", "start": start_time.strftime("%Y%m%dT%H%M%SZ"), "end": end_time.strftime("%Y%m%dT%H%M%SZ") }, "etag": 1770368451507 }
url = f'https://gateway.maton.ai/zoho-calendar/api/v1/calendars/fda9b0b4ad834257b622cb3dc3555727/events/[email protected]?eventdata={urllib.parse.quote(json.dumps(eventdata))}' req = urllib.request.Request(url, method='PUT') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
#### Delete Event
```bash DELETE /zoho-calendar/api/v1/calendars/{calendar_uid}/events/{event_uid} ```
**Required Header:** - `etag` - 事件的当前 etag 值
**Example:**
```bash python <<'EOF' import urllib.request, os, json
req = urllib.request.Request('https://gateway.maton.ai/zoho-calendar/api/v1/calendars/fda9b0b4ad834257b622cb3dc3555727/events/[email protected]', method='DELETE') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') req.add_header('etag', '1770368451507') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
**Response:** ```json { "events": [ { "uid": "[email protected]", "estatus": "deleted", "caluid": "fda9b0b4ad834257b622cb3dc3555727" } ] } ```
### Attendees
创建或更新事件时,请包含参会者:
```json { "attendees": [ { "email": "[email protected]", "permission": 1, "attendance": 1 } ] } ```
**Permission levels:** 0 (访客), 1 (查看), 2 (邀请), 3 (编辑) **Attendance:** 0 (非参与者), 1 (必需), 2 (可选)
### Reminders
```json { "reminders": [ { "action": "popup", "minutes": 30 }, { "action": "email", "minutes": 60 } ] } ```
**Actions:** `email`, `popup`, `notification`
### Recurring Events
使用 iCalendar RRULE 格式的 `rrule` 字段:
```json { "rrule": "FREQ=DAILY;COUNT=5;INTERVAL=1" } ```
**Examples:** - 每天持续 5 天:`FREQ=DAILY;COUNT=5;INTERVAL=1` - 每周一/周二:`FREQ=WEEKLY;INTERVAL=1;BYDAY=MO,TU;UNTIL=20250817T064600Z` - 每月最后一个周二:`FREQ=MONTHLY;INTERVAL=1;BYDAY=TU;BYSETPOS=-1;COUNT=2`
## Code Examples
### JavaScript
```javascript const response = await fetch( 'https://gateway.maton.ai/zoho-calendar/api/v1/calendars', { headers: { 'Authorization': `Bearer ${process.env.MATON_API_KEY}` } } ); const data = await response.json(); ```
### Python
```python import os import requests
response = requests.get( 'https://gateway.maton.ai/zoho-calendar/api/v1/calendars', headers={'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'} ) data = response.json() ```
## Notes
- 事件和日历数据作为 JSON 在 `eventdata` 或 `calendarData` 查询参数中传递 - 事件的日期/时间格式:`yyyyMMdd'T'HHmmss'Z'` (GMT) 或全天事件的 `yyyyMMdd` - 列出事件的 `range` 参数不能超过 31 天 - 更新和删除操作需要 `etag` - 修改前务必获取最新的 etag - 对于删除操作,`etag` 必须作为头传递,而不是查询参数 - 重要:使用 curl 命令时,如果 URL 包含括号,请使用 `curl -g` 以禁用 glob 解析 - 重要:当将 curl 输出通过管道传递给 `jq` 或其他命令时,像 `$MATON_API_KEY` 这样的环境变量在某些 shell 环境中可能无法正确展开
## Error Handling
| Status | Meaning | |--------|---------| | 400 | 缺少 Zoho Calendar 连接、缺少必需参数或请求无效 | | 401 | Maton API 密钥无效或缺失,或 OAuth 范围不匹配 | | 404 | 未找到资源 | | 429 | 速率受限 | | 4xx/5xx | 来自 Zoho Calendar API 的透传错误 |
### Common Errors
| Error | Description | |-------|-------------| | `ETAG_MISSING` | 删除操作需要 etag 头 | | `EXTRA_PARAM_FOUND` | 请求中存在无效参数 | | `INVALID_DATA` | 请求数据格式错误 |
### Troubleshooting: API Key Issues
1. 检查是否已设置 `MATON_API_KEY` 环境变量:
```bash echo $MATON_API_KEY ```
2. 通过列出连接验证 API 密钥是否有效:
```bash python <<'EOF' import urllib.request, os, json req = urllib.request.Request('https://ctrl.maton.ai/connections') req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}') print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2)) EOF ```
### Troubleshooting: Invalid App Name
1. 确保您的 URL 路径以 `zoho-calendar` 开头。例如:
- 正确:`https://gateway.maton.ai/zoho-calendar/api/v1/calendars` - 错误:`https://gateway.maton.ai/api/v1/calendars`
## Resources
- [Zoho Calendar API Introduction](https://www.zoho.com/calendar/help/api/introduction.html) - [Zoho Calendar Events API](https://www.zoho.com/calendar/help/api/events-api.html) - [Zoho Calendar Calendars API](https://www.zoho.com/calendar/help/api/calendars-api.html) - [Create Event](https://www.zoho.com/calendar/help/api/post-create-event.html) - [Get Events List](https://www.zoho.com/calendar/help/api/get-events-list.html) - [Maton Community](https://discord.com/invite/dBfFAcefs2) - [Maton Support](mailto:[email protected])