---
title: "List events in a calendar"
method: GET
path: "/v1/calendars/{cal_id}/events"
tags: ["Events"]
---

# List events in a calendar

`GET /v1/calendars/{cal_id}/events`

## Request

- Base URL: `https://api.chronary.ai`
- URL: `https://api.chronary.ai/v1/calendars/{cal_id}/events`
- Auth: HTTP bearer

## Path parameters

- `cal_id` string, required: Calendar ID

## Query parameters

- `start_after` string, date-time
- `start_before` string, date-time
- `status` 'confirmed' | 'tentative' | 'cancelled' | 'hold'
- `source` 'internal' | 'external_ical'
- `limit` integer
- `offset` integer, nullable
- `expand` 'true' | 'false'

## Response `200`

List of events

- EventList
  - `data` Event[], required
    - `id` string, required
    - `calendarId` string, required
    - `orgId` string, required
    - `title` string, required
    - `description` string, nullable, required
    - `startTime` string, date-time, required
    - `endTime` string, date-time, required
    - `allDay` boolean, required
    - `status` 'confirmed' | 'tentative' | 'cancelled' | 'hold', required
    - `source` 'internal' | 'external_ical', required
    - `metadata` object, required
    - `reminders` integer[], nullable, required: Reminder offsets (minutes before start). Each fires an event.reminder webhook and emits a VALARM in the iCal feed. null = inherit the calendar default (then the system default of 10 min); [] = no reminders.
    - `holdExpiresAt` string, date-time, nullable, required: When set, the event is a tentative hold that auto-expires at this timestamp. Must be 30 seconds to 15 minutes in the future when creating a hold; the cap exists to keep held slots short enough that they do not block real scheduling for long.
    - `holdPriority` integer, nullable, required: Priority for conflict resolution. Higher values pre-empt lower-priority overlapping holds.
    - `recurrenceRule` string, nullable, required: RFC 5545 RRULE subset (no "RRULE:" prefix) when this event is a recurring series master, e.g. "FREQ=WEEKLY;BYDAY=MO,WE;COUNT=12". Expansion is UTC-only. null = one-off event.
    - `recurrenceExdates` string[], required: ISO 8601 starts of individually cancelled occurrences (EXDATE).
    - `recurringEventId` string: Present only on expanded instances (expand=true): the id of the recurring series master this instance belongs to.
    - `originalStartTime` string, date-time: Present only on expanded instances: the occurrence start this instance was generated for.
    - `external_sync` object: Present only on create/update/hold mutation responses — the outcome of publishing this event to a connected human calendar (opt-in). Absent on read/list responses.
      - `status` string, required: not_configured | queued | published | skipped | failed
    - `deletedAt` string, date-time, nullable, required
    - `createdAt` string, date-time, required
    - `updatedAt` string, date-time, required
  - `total` integer, required
  - `limit` integer, required
  - `offset` integer, required

## Other responses

- `401`: Unauthorized — missing or invalid API key
- `404`: Resource not found
- `429`: Rate limited — 10 requests per second per key exceeded
- `500`: Internal server error

---

[API](https://skmtc.dev/chronary/apis/chronary-api.md) · [All operations](https://skmtc.dev/chronary/apis/chronary-api/llms.txt) · [OpenAPI document](https://skmtc.dev/chronary/apis/chronary-api/revisions/0d1a330294ae?raw)
