{ "paths": { "/events": { "get": { "tags": ["Events"], "summary": "List events", "description": "Returns events within a time range across all accessible calendars. Recurring events are expanded into individual occurrences within the requested range. Supports filtering by calendar, search text, and tags. Uses cursor-based pagination. Requires `events:read` scope.", "operationId": "listEvents", "parameters": [ { "name": "start", "in": "query", "required": true, "schema": { "type": "string", "format": "date-time" }, "description": "Range start (RFC3339)" }, { "name": "end", "in": "query", "required": true, "schema": { "type": "string", "format": "date-time" }, "description": "Range end (RFC3339)" }, { "name": "calendar_id", "in": "query", "schema": { "type": "string", "format": "uuid" }, "description": "Filter by calendar" }, { "name": "search", "in": "query", "schema": { "type": "string" }, "description": "Full-text search on title/description" }, { "name": "tag", "in": "query", "schema": { "type": "string" }, "description": "Filter by tag" }, { "name": "limit", "in": "query", "schema": { "type": "integer", "minimum": 1, "maximum": 200, "default": 50 }, "description": "Page size" }, { "name": "cursor", "in": "query", "schema": { "type": "string" }, "description": "Pagination cursor from previous response" } ], "responses": { "200": { "description": "List of events (including expanded recurrence occurrences)", "content": { "application/json": { "schema": { "type": "object", "required": ["items", "page"], "properties": { "items": { "type": "array", "items": { "$ref": "#/components/schemas/Event" } }, "page": { "$ref": "#/components/schemas/PageInfo" } } } } } }, "400": { "description": "Validation error (e.g. missing start/end, range too large)", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "post": { "tags": ["Events"], "summary": "Create an event", "description": "Creates a new event on the specified calendar. Times are converted to UTC for storage. Supports recurrence rules (RFC5545 RRULE), reminders, and tags. User must have editor or owner role on the calendar. Requires `events:write` scope.", "operationId": "createEvent", "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["calendar_id", "title", "start_time", "end_time", "timezone"], "properties": { "calendar_id": { "type": "string", "format": "uuid" }, "title": { "type": "string", "minLength": 1, "maxLength": 140, "example": "Meeting" }, "description": { "type": "string", "example": "Project sync" }, "location": { "type": "string", "example": "Zoom" }, "start_time": { "type": "string", "format": "date-time", "example": "2026-03-01T14:00:00-03:00" }, "end_time": { "type": "string", "format": "date-time", "example": "2026-03-01T15:00:00-03:00" }, "timezone": { "type": "string", "example": "America/Asuncion" }, "all_day": { "type": "boolean", "default": false }, "recurrence_rule": { "type": "string", "nullable": true, "example": "FREQ=WEEKLY;BYDAY=MO,WE,FR" }, "reminders": { "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 10080 }, "description": "Minutes before event to remind", "example": [10, 60] }, "tags": { "type": "array", "items": { "type": "string" }, "example": ["work", "sync"] } } } } } }, "responses": { "200": { "description": "Event created", "content": { "application/json": { "schema": { "type": "object", "required": ["event"], "properties": { "event": { "$ref": "#/components/schemas/Event" } } } } } }, "400": { "description": "Validation error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope or calendar permission", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/events/{id}": { "get": { "tags": ["Events"], "summary": "Get an event", "description": "Returns a single event by ID with all related data (reminders, attendees, tags, attachments). Requires `events:read` scope.", "operationId": "getEvent", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Event ID" } ], "responses": { "200": { "description": "Event details", "content": { "application/json": { "schema": { "type": "object", "required": ["event"], "properties": { "event": { "$ref": "#/components/schemas/Event" } } } } } }, "401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope or permission", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Event not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "put": { "tags": ["Events"], "summary": "Update an event", "description": "Updates an existing event. Times are re-validated and converted to UTC. If recurrence rule changes, it is re-validated. Reminders are rescheduled. Requires `events:write` scope and editor/owner role.", "operationId": "updateEvent", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Event ID" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "properties": { "title": { "type": "string", "minLength": 1, "maxLength": 140 }, "description": { "type": "string", "nullable": true }, "location": { "type": "string", "nullable": true }, "start_time": { "type": "string", "format": "date-time" }, "end_time": { "type": "string", "format": "date-time" }, "timezone": { "type": "string" }, "all_day": { "type": "boolean" }, "recurrence_rule": { "type": "string", "nullable": true }, "tags": { "type": "array", "items": { "type": "string" } } } } } } }, "responses": { "200": { "description": "Event updated", "content": { "application/json": { "schema": { "type": "object", "required": ["event"], "properties": { "event": { "$ref": "#/components/schemas/Event" } } } } } }, "400": { "description": "Validation error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope or permission", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Event not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "tags": ["Events"], "summary": "Delete an event", "description": "Soft-deletes an event. Requires `events:write` scope and editor/owner role on the calendar.", "operationId": "deleteEvent", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Event ID" } ], "responses": { "200": { "description": "Event deleted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } } }, "401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope or permission", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Event not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/events/{id}/reminders": { "post": { "tags": ["Reminders"], "summary": "Add reminders to an event", "description": "Adds one or more reminders to an event, specified as minutes before the event start. Background jobs are scheduled for each reminder. Requires `events:write` scope.", "operationId": "addReminders", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Event ID" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["minutes_before"], "properties": { "minutes_before": { "type": "array", "items": { "type": "integer", "minimum": 0, "maximum": 10080 }, "example": [5, 15, 60] } } } } } }, "responses": { "200": { "description": "Reminders added, returns updated event", "content": { "application/json": { "schema": { "type": "object", "required": ["event"], "properties": { "event": { "$ref": "#/components/schemas/Event" } } } } } }, "400": { "description": "Validation error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope or permission", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Event not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/events/{id}/reminders/{reminderID}": { "delete": { "tags": ["Reminders"], "summary": "Delete a reminder", "description": "Removes a specific reminder from an event. Requires `events:write` scope.", "operationId": "deleteReminder", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Event ID" }, { "name": "reminderID", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Reminder ID" } ], "responses": { "200": { "description": "Reminder deleted", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } } }, "401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope or permission", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Event or reminder not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/events/{id}/attendees": { "post": { "tags": ["Attendees"], "summary": "Add attendees to an event", "description": "Adds one or more attendees to an event, identified by email or user ID. Initial status is `pending`. Requires `events:write` scope.", "operationId": "addAttendees", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Event ID" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["attendees"], "properties": { "attendees": { "type": "array", "items": { "type": "object", "properties": { "email": { "type": "string", "format": "email" }, "user_id": { "type": "string", "format": "uuid" } } }, "example": [ { "email": "guest@example.com" }, { "user_id": "550e8400-e29b-41d4-a716-446655440000" } ] } } } } } }, "responses": { "200": { "description": "Attendees added, returns updated event", "content": { "application/json": { "schema": { "type": "object", "required": ["event"], "properties": { "event": { "$ref": "#/components/schemas/Event" } } } } } }, "400": { "description": "Validation error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope or permission", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Event not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } }, "/events/{id}/attendees/{attendeeID}": { "put": { "tags": ["Attendees"], "summary": "Update attendee status", "description": "Updates an attendee's RSVP status. The event organizer can update any attendee; attendees can update their own status. Requires `events:write` scope.", "operationId": "updateAttendeeStatus", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Event ID" }, { "name": "attendeeID", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Attendee ID" } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["status"], "properties": { "status": { "type": "string", "enum": ["accepted", "declined", "tentative"] } } } } } }, "responses": { "200": { "description": "Attendee updated, returns updated event", "content": { "application/json": { "schema": { "type": "object", "required": ["event"], "properties": { "event": { "$ref": "#/components/schemas/Event" } } } } } }, "400": { "description": "Validation error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope or permission", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Event or attendee not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } }, "delete": { "tags": ["Attendees"], "summary": "Remove an attendee", "description": "Removes an attendee from an event. Requires `events:write` scope.", "operationId": "deleteAttendee", "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Event ID" }, { "name": "attendeeID", "in": "path", "required": true, "schema": { "type": "string", "format": "uuid" }, "description": "Attendee ID" } ], "responses": { "200": { "description": "Attendee removed", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/OkResponse" } } } }, "401": { "description": "Not authenticated", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "403": { "description": "Insufficient scope or permission", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } }, "404": { "description": "Event or attendee not found", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } } } } } } }