Skip to content

Events

Base path: /api/v1/events

POST /events

Body:

FieldTypeRequiredDefaultDescription
titlestringYes
descriptionstringNonull
locationstringNonull
start_atdatetime (ISO 8601)Yes
end_atdatetimeNonullDefaults to 1 hour after start_at if omitted and all_day is false
all_daybooleanNofalse
recurrenceobjectNonullRFC 5545 RRULE structure (see below)
statusstringNo"confirmed"confirmed, tentative, cancelled
calendar_namestringNo"default"For multi-calendar support
remindersobject[]No[][{type, minutes_before}]
attendeesobject[]No[][{email, name, status}] — status: accepted, declined, tentative, pending
custom_fieldsobjectNonullArbitrary key-value data

Response: 201 Created with the full event object.

WebSocket event: event.created

The recurrence object follows RFC 5545 RRULE conventions:

{
"freq": "weekly",
"byday": ["MO", "WE", "FR"],
"until": "2026-06-30"
}
{
"title": "Weekly standup",
"location": "Discord",
"start_at": "2026-02-17T09:00:00Z",
"end_at": "2026-02-17T09:30:00Z",
"recurrence": { "freq": "weekly", "byday": ["MO"], "until": "2026-06-30" },
"reminders": [{ "type": "notification", "minutes_before": 10 }],
"attendees": [{ "email": "[email protected]", "name": "Ana", "status": "accepted" }]
}

GET /events

Query parameters:

ParameterTypeDefaultDescription
limitinteger20
offsetinteger0
sortstringstart_atValid: start_at, created_at, updated_at, title
orderstringascNote: defaults to asc (chronological)
searchstringFull-text search on title and description
datestringConvenience filter: today, tomorrow, this_week, this_month, or ISO date (2026-02-17)
fromdatetimeEvents starting from this date (inclusive)
todatetimeEvents starting up to this date (inclusive)
calendar_namestringFilter by calendar name
statusstringFilter by status
sourcestringFilter by origin
include_deletedbooleanfalseInclude soft-deleted events
only_deletedbooleanfalseOnly soft-deleted events (trash view)

Response: 200 OK with list envelope.

Supports ?format=compact for token-optimized output.

GET /events/:id

Response: 200 OK with single record envelope.

Returns 404 NOT_FOUND if the event doesn’t exist or is soft-deleted.

PATCH /events/:id

Send only the fields to update.

Updatable fields: title, description, location, start_at, end_at, all_day, recurrence, status, calendar_name, reminders, attendees, custom_fields

Response: 200 OK with the full updated event.

WebSocket event: event.updated

PATCH /events/:id/custom

Incremental update via shallow merge. Same behavior as Notes custom fields.

Response: 200 OK with the full event.

WebSocket event: event.updated

DELETE /events/:id — soft delete (sets deleted_at)

DELETE /events/:id?permanent=true — permanent delete (irreversible)

See Soft Deletes for details.

WebSocket event: event.deleted

POST /events/:id/restore — clears deleted_at, event reappears in listings.

WebSocket event: event.restored