Install
openclaw skills install google-calendar-apiGoogle Calendar API integration with managed OAuth. Create events, list calendars, check availability, and manage schedules. Use this skill when users want to interact with Google Calendar. For other third party apps, use the api-gateway skill (https://clawhub.ai/byungkyu/api-gateway).
openclaw skills install google-calendar-apiAccess the Google Calendar API with managed OAuth authentication. Create and manage events, list calendars, and check availability.
Show today's events on the primary calendar.
CLI:
# Show today's agenda (defaults to primary calendar when -c is omitted)
maton google-calendar agenda --today
maton api '/google-calendar/calendar/v3/calendars/primary/events?singleEvents=true&orderBy=startTime&timeMin=2026-05-05T00:00:00Z&timeMax=2026-05-06T00:00:00Z'
Python:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/google-calendar/calendar/v3/calendars/primary/events?singleEvents=true&orderBy=startTime&timeMin=2026-05-05T00:00:00Z&timeMax=2026-05-06T00:00:00Z')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
https://api.maton.ai/google-calendar/{native-api-path}
Maton proxies requests to www.googleapis.com and automatically injects your OAuth token.
NPM:
npm install -g @maton-ai/cli
Homebrew:
brew install maton-ai/cli/maton
CLI:
maton login # Opens browser for API key
maton login --interactive # Skip browser, paste API key directly
maton whoami # Show current auth state
Manual:
MATON_API_KEY:export MATON_API_KEY="YOUR_API_KEY"
Manage your Google OAuth connections at https://api.maton.ai.
CLI:
maton connection list google-calendar --status ACTIVE
maton api -X GET /connections -f app=google-calendar -f status=ACTIVE
Python:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/connections?app=google-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
CLI:
maton connection create google-calendar
maton api /connections -f app=google-calendar
Python:
python <<'EOF'
import urllib.request, os, json
data = json.dumps({'app': 'google-calendar'}).encode()
req = urllib.request.Request('https://api.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
CLI:
maton connection view {connection_id}
maton api /connections/{connection_id}
Python:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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:
{
"connection": {
"connection_id": "{connection_id}",
"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": "google-calendar",
"metadata": {}
}
}
Open the returned url in a browser to complete OAuth authorization.
CLI:
maton connection delete {connection_id}
maton api -X DELETE /connections/{connection_id}
Python:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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
If you have multiple Google Calendar connections, specify which one to use:
CLI:
maton google-calendar event list -c primary --connection {connection_id}
maton api /google-calendar/calendar/v3/calendars/primary/events --connection {connection_id}
Python:
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.maton.ai/google-calendar/calendar/v3/calendars/primary/events')
req.add_header('Authorization', f'Bearer {os.environ["MATON_API_KEY"]}')
req.add_header('Maton-Connection', '{connection_id}')
print(json.dumps(json.load(urllib.request.urlopen(req)), indent=2))
EOF
If you have multiple connections, always specify the connection to ensure requests go to the intended account.
GET /google-calendar/calendar/v3/users/me/calendarList
Example:
maton google-calendar calendar list
GET /google-calendar/calendar/v3/calendars/{calendarId}
Example:
maton google-calendar calendar view primary
GET /google-calendar/calendar/v3/calendars/team@example.com/events?maxResults=10&orderBy=startTime&singleEvents=true
With time bounds:
GET /google-calendar/calendar/v3/calendars/team@example.com/events?timeMin=2024-01-01T00:00:00Z&timeMax=2024-12-31T23:59:59Z&singleEvents=true&orderBy=startTime
Example:
maton google-calendar event list -c team@example.com --time-min 2026-06-17T00:00:00Z --time-max 2026-06-18T00:00:00Z
GET /google-calendar/calendar/v3/calendars/primary/events/{eventId}
Example:
maton google-calendar event view EVENT_ID
POST /google-calendar/calendar/v3/calendars/primary/events
Content-Type: application/json
{
"summary": "Team Meeting",
"description": "Weekly sync",
"start": {
"dateTime": "2024-01-15T10:00:00",
"timeZone": "America/Los_Angeles"
},
"end": {
"dateTime": "2024-01-15T11:00:00",
"timeZone": "America/Los_Angeles"
},
"attendees": [
{"email": "attendee@example.com"}
]
}
Example:
maton google-calendar event create --summary 'Team Meeting' --description 'Weekly sync' --start 2024-01-15T10:00:00-08:00 --end 2024-01-15T11:00:00-08:00 --attendee attendee@example.com
POST /google-calendar/calendar/v3/calendars/primary/events
Content-Type: application/json
{
"summary": "All Day Event",
"start": {"date": "2024-01-15"},
"end": {"date": "2024-01-16"}
}
PUT /google-calendar/calendar/v3/calendars/primary/events/{eventId}
Content-Type: application/json
{
"summary": "Updated Meeting Title",
"start": {"dateTime": "2024-01-15T10:00:00Z"},
"end": {"dateTime": "2024-01-15T11:00:00Z"}
}
Example:
maton google-calendar event update EVENT_ID --summary 'Updated Meeting Title' --start 2024-01-15T10:00:00Z --end 2024-01-15T11:00:00Z
PATCH /google-calendar/calendar/v3/calendars/primary/events/{eventId}
Content-Type: application/json
{
"summary": "New Title Only"
}
Example:
maton google-calendar event update EVENT_ID --summary 'New Title Only'
DELETE /google-calendar/calendar/v3/calendars/primary/events/{eventId}
Example:
maton google-calendar event delete EVENT_ID
POST /google-calendar/calendar/v3/calendars/primary/events/quickAdd?text=Meeting+with+John+tomorrow+at+3pm
Example:
maton google-calendar event quick-add --text 'Meeting with John tomorrow at 3pm'
POST /google-calendar/calendar/v3/freeBusy
Content-Type: application/json
{
"timeMin": "2024-01-15T00:00:00Z",
"timeMax": "2024-01-16T00:00:00Z",
"items": [{"id": "primary"}]
}
Example:
maton google-calendar freebusy query --time-min 2024-01-15T00:00:00Z --time-max 2024-01-16T00:00:00Z
Google Calendar uses token-based pagination. The CLI automatically paginates with '--paginate'.
Example:
maton google-calendar event list --paginate
# Show today's agenda (defaults to primary calendar when -c is omitted)
maton google-calendar agenda --today
# Filter with jq
maton google-calendar event list --json --jq '.items[] | {summary: .summary, start: .start.dateTime}'
# Extract specific fields
maton google-calendar calendar list --json --jq '.items[].summary'
// List events
const response = await fetch(
'https://api.maton.ai/google-calendar/calendar/v3/calendars/primary/events?maxResults=10&singleEvents=true',
{
headers: {
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
}
}
);
// Create event
await fetch(
'https://api.maton.ai/google-calendar/calendar/v3/calendars/primary/events',
{
method: 'POST',
headers: {
'Content-Type': 'application/json',
'Authorization': `Bearer ${process.env.MATON_API_KEY}`
},
body: JSON.stringify({
summary: 'Meeting',
start: { dateTime: '2024-01-15T10:00:00Z' },
end: { dateTime: '2024-01-15T11:00:00Z' }
})
}
);
import os
import requests
headers = {'Authorization': f'Bearer {os.environ["MATON_API_KEY"]}'}
# List events
events = requests.get(
'https://api.maton.ai/google-calendar/calendar/v3/calendars/primary/events',
headers=headers,
params={'maxResults': 10, 'singleEvents': 'true'}
).json()
# Create event
response = requests.post(
'https://api.maton.ai/google-calendar/calendar/v3/calendars/primary/events',
headers=headers,
json={
'summary': 'Meeting',
'start': {'dateTime': '2024-01-15T10:00:00Z'},
'end': {'dateTime': '2024-01-15T11:00:00Z'}
}
)
2024-01-15T10:00:00Z)singleEvents=true to expand instancesorderBy=startTime requires singleEvents=truecurl -g when URLs contain brackets (fields[], sort[], records[]) to disable glob parsingjq or other commands, environment variables like $MATON_API_KEY may not expand correctly in some shell environments. You may get "Invalid API key" errors when piping.| Status | Meaning |
|---|---|
| 400 | Missing Google Calendar connection |
| 401 | Invalid or missing Maton API key |
| 429 | Rate limited (10 req/sec per account) |
| 4xx/5xx | Passthrough error from Google Calendar API |
CLI:
maton whoami
maton connection list
Manual:
MATON_API_KEY environment variable is set:echo $MATON_API_KEY
python <<'EOF'
import urllib.request, os, json
req = urllib.request.Request('https://api.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
google-calendar. For example:https://api.maton.ai/google-calendar/calendar/v3/calendars/primary/eventshttps://api.maton.ai/calendar/v3/calendars/primary/events