Calendar events. The DB row is the source of truth; Google Calendar is a best-effort mirror on writes.
GET/api/v1/events
Scope: calendar:read. Query params: start_date, end_date (both YYYY-MM-DD), limit (default 100, max 100), offset.
// Response
{
events: Array<{
id: string;
title: string;
date: string; // YYYY-MM-DD
start_time: string; // HH:mm:ss
end_time: string;
timezone: string;
attendees: string[];
description: string;
location: string;
meeting_link: string | null;
bucket_id: string | null;
created_at: string;
}>;
pagination: { limit: number; offset: number; hasMore: boolean };
}
POST/api/v1/events
Scope: calendar:write. Required: title, date (YYYY-MM-DD), start_time, end_time (HH:mm or HH:mm:ss). Optional: attendees, description, location, bucket_id, add_meet (boolean, requests a Google Meet link).
// Request body
{
title: string;
date: string; // "YYYY-MM-DD"
start_time: string; // "HH:mm" or "HH:mm:ss"
end_time: string;
attendees?: string[];
description?: string;
location?: string;
bucket_id?: string | null;
add_meet?: boolean;
}
// Response (201)
{
event: {
id: string;
title, date, start_time, end_time, timezone,
attendees, description, location,
meeting_link: string | null;
gcal_event_id: string | null;
gcal_link: string | null;
bucket_id: string | null;
created_at: string;
};
gcal_warning: string | null;
}
The DB write is never blocked on Google Calendar. If the GCal mirror fails (expired refresh token, revoked grant, GCal outage), the event is still created in Malleable and the response includes a non-null gcal_warning string with the underlying error message. Clients should surface this so the user knows to reconnect Google Calendar at malleable.cloud/settings/integrations. If the user has never connected GCal at all, the request fails up-front with CALENDAR_NOT_CONNECTED.
curl -X POST https://malleable.cloud/api/v1/events \
-H "Authorization: Bearer mk_live_..." \
-H "Content-Type: application/json" \
-d '{
"title": "Design review",
"date": "2026-05-10",
"start_time": "14:00",
"end_time": "15:00",
"add_meet": true
}'
DELETE/api/v1/events/{id}
Scope: calendar:write. Deletes the event row and best-effort deletes the GCal mirror. Returns { ok: true } on success or EVENT_NOT_FOUND (404) if the event is not owned by the caller.