Events
Events are the individual entries on a calendar — meetings, appointments, tasks, or any time-boxed item your agent needs to track.
What you’ll accomplish
Section titled “What you’ll accomplish”By the end of this guide you will be able to create events on a calendar, list and filter them, query across an agent’s calendars, update event details, and delete events.
Prerequisites
Section titled “Prerequisites”- A Chronary account with an API key
- At least one agent and calendar created (see the quickstart)
Create an event
Section titled “Create an event”curl -X POST https://api.chronary.ai/v1/calendars/cal_x1y2z3/events \ -H "Authorization: Bearer chr_sk_your_key_here" \ -H "Content-Type: application/json" \ -d '{ "title": "Product demo with Globex Industries", "start_time": "2026-04-10T15:00:00Z", "end_time": "2026-04-10T16:00:00Z", "description": "Walk through the new dashboard features and pricing tiers", "status": "confirmed", "metadata": { "deal_id": "deal_9823", "attendees": ["[email protected]", "[email protected]"] } }'chronary events create \ --calendar cal_x1y2z3 \ --title "Product demo with Globex Industries" \ --start "2026-04-10T15:00:00Z" \ --end "2026-04-10T16:00:00Z" \ --description "Walk through the new dashboard features and pricing tiers" \ --status confirmed \# Created event evt_m1n2o3 (Product demo with Globex Industries)const response = await fetch( 'https://api.chronary.ai/v1/calendars/cal_x1y2z3/events', { method: 'POST', headers: { 'Authorization': 'Bearer chr_sk_your_key_here', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Product demo with Globex Industries', start_time: '2026-04-10T15:00:00Z', end_time: '2026-04-10T16:00:00Z', description: 'Walk through the new dashboard features and pricing tiers', status: 'confirmed', metadata: { deal_id: 'deal_9823', }, }), });const event = await response.json();console.log(event.id); // "evt_m1n2o3"from chronary import Chronary
client = Chronary()
event = client.events.create( calendar_id="cal_x1y2z3", title="Product demo with Globex Industries", start_time="2026-04-10T15:00:00Z", end_time="2026-04-10T16:00:00Z", description="Walk through the new dashboard features and pricing tiers", status="confirmed", metadata={ "deal_id": "deal_9823", },)print(event.id) # "evt_m1n2o3"You can also create all-day events by setting all_day: true and providing dates without times:
{ "title": "Company offsite", "start_time": "2026-04-15T00:00:00Z", "end_time": "2026-04-17T00:00:00Z", "all_day": true}List events on a calendar
Section titled “List events on a calendar”Retrieve events for a specific calendar with optional filters.
curl "https://api.chronary.ai/v1/calendars/cal_x1y2z3/events?start_after=2026-04-07T00:00:00Z&start_before=2026-04-14T00:00:00Z&status=confirmed&limit=20" \ -H "Authorization: Bearer chr_sk_your_key_here"chronary events list \ --calendar cal_x1y2z3 \ --start-after "2026-04-07T00:00:00Z" \ --start-before "2026-04-14T00:00:00Z" \ --status confirmed \ --limit 20const params = new URLSearchParams({ start_after: '2026-04-07T00:00:00Z', start_before: '2026-04-14T00:00:00Z', status: 'confirmed', limit: '20',});const response = await fetch( `https://api.chronary.ai/v1/calendars/cal_x1y2z3/events?${params}`, { headers: { 'Authorization': 'Bearer chr_sk_your_key_here' } });const { data, total, limit, offset } = await response.json();console.log(`Showing ${data.length} of ${total} events`);events = client.events.list( calendar_id="cal_x1y2z3", start_after="2026-04-07T00:00:00Z", start_before="2026-04-14T00:00:00Z", status="confirmed", limit=20,)for event in events: print(event.title)Filter parameters:
| Parameter | Type | Description |
|---|---|---|
start_after | ISO 8601 | Only events starting after this time |
start_before | ISO 8601 | Only events starting before this time |
status | string | Filter by status: confirmed, tentative, cancelled |
source | string | Filter by source: api, external_ical |
limit | integer | Results per page (default: 50, max: 200) |
offset | integer | Number of results to skip for pagination |
expand | boolean | Expand recurring series into individual occurrences (requires both start_after and start_before, window up to 366 days) — see Recurring events |
List events across an agent’s calendars
Section titled “List events across an agent’s calendars”Query all events across every calendar owned by an agent. This is useful when an agent has multiple calendars and you need a unified view.
curl "https://api.chronary.ai/v1/agents/agt_a1b2c3d4/events?start_after=2026-04-07T00:00:00Z&limit=50" \ -H "Authorization: Bearer chr_sk_your_key_here"const params = new URLSearchParams({ start_after: '2026-04-07T00:00:00Z', limit: '50',});const response = await fetch( `https://api.chronary.ai/v1/agents/agt_a1b2c3d4/events?${params}`, { headers: { 'Authorization': 'Bearer chr_sk_your_key_here' } });const { data } = await response.json();// Events from all of this agent's calendars# Events from all of this agent's calendarsfor event in client.agents.events.list( "agt_a1b2c3d4", start_after="2026-04-07T00:00:00Z",): print(f"{event.title} ({event.calendar_id})")Get a single event
Section titled “Get a single event”curl https://api.chronary.ai/v1/calendars/cal_x1y2z3/events/evt_m1n2o3 \ -H "Authorization: Bearer chr_sk_your_key_here"const response = await fetch( 'https://api.chronary.ai/v1/calendars/cal_x1y2z3/events/evt_m1n2o3', { headers: { 'Authorization': 'Bearer chr_sk_your_key_here' } });const event = await response.json();event = client.events.get("cal_x1y2z3", "evt_m1n2o3")Update an event
Section titled “Update an event”Only the fields you include in the request body are updated. Omitted fields remain unchanged.
curl -X PATCH https://api.chronary.ai/v1/calendars/cal_x1y2z3/events/evt_m1n2o3 \ -H "Authorization: Bearer chr_sk_your_key_here" \ -H "Content-Type: application/json" \ -d '{ "title": "Product demo with Globex Industries (rescheduled)", "start_time": "2026-04-11T15:00:00Z", "end_time": "2026-04-11T16:00:00Z" }'const response = await fetch( 'https://api.chronary.ai/v1/calendars/cal_x1y2z3/events/evt_m1n2o3', { method: 'PATCH', headers: { 'Authorization': 'Bearer chr_sk_your_key_here', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Product demo with Globex Industries (rescheduled)', start_time: '2026-04-11T15:00:00Z', end_time: '2026-04-11T16:00:00Z', }), });const updated = await response.json();updated = client.events.update( "cal_x1y2z3", "evt_m1n2o3", title="Product demo with Globex Industries (rescheduled)", start_time="2026-04-11T15:00:00Z", end_time="2026-04-11T16:00:00Z",)Delete an event
Section titled “Delete an event”curl -X DELETE https://api.chronary.ai/v1/calendars/cal_x1y2z3/events/evt_m1n2o3 \ -H "Authorization: Bearer chr_sk_your_key_here"await fetch( 'https://api.chronary.ai/v1/calendars/cal_x1y2z3/events/evt_m1n2o3', { method: 'DELETE', headers: { 'Authorization': 'Bearer chr_sk_your_key_here' }, });// Returns 204 No Content on successclient.events.delete("cal_x1y2z3", "evt_m1n2o3")# Returns None on successRecurring events
Section titled “Recurring events”Add a recurrence_rule (an RFC 5545 RRULE subset, without the RRULE: prefix) to make an event repeat. A series is stored as a single event and counts once toward your monthly events quota.
curl -X POST https://api.chronary.ai/v1/calendars/cal_x1y2z3/events \ -H "Authorization: Bearer chr_sk_your_key_here" \ -H "Content-Type: application/json" \ -d '{ "title": "Weekly pipeline review", "start_time": "2026-04-13T09:00:00Z", "end_time": "2026-04-13T09:30:00Z", "recurrence_rule": "FREQ=WEEKLY;BYDAY=MO;COUNT=12" }'const response = await fetch( 'https://api.chronary.ai/v1/calendars/cal_x1y2z3/events', { method: 'POST', headers: { 'Authorization': 'Bearer chr_sk_your_key_here', 'Content-Type': 'application/json', }, body: JSON.stringify({ title: 'Weekly pipeline review', start_time: '2026-04-13T09:00:00Z', end_time: '2026-04-13T09:30:00Z', recurrence_rule: 'FREQ=WEEKLY;BYDAY=MO;COUNT=12', }), });const series = await response.json();console.log(series.recurrenceRule); // "FREQ=WEEKLY;BYDAY=MO;COUNT=12"Common rules:
| Goal | Rule |
|---|---|
| Every day for two weeks | FREQ=DAILY;COUNT=14 |
| Mon/Wed/Fri standups until June | FREQ=WEEKLY;BYDAY=MO,WE,FR;UNTIL=20260630 |
| Every other week | FREQ=WEEKLY;INTERVAL=2;COUNT=10 |
| Second Tuesday of each month | FREQ=MONTHLY;BYDAY=2TU;COUNT=6 |
| Last day of each month | FREQ=MONTHLY;BYMONTHDAY=-1;COUNT=12 |
Three things to keep in mind:
start_timeis the first occurrence and must match the rule (aBYDAY=MOrule needs a Mondaystart_time).- Expansion is UTC-only — “every Monday 09:00” means 09:00 UTC year-round; the series does not track daylight-saving changes.
- Plan limits — Free allows 5 active series and every rule must be bounded (
COUNTorUNTIL) ending within 90 days of the series start; Pro allows 250 series with unbounded rules.
See individual occurrences
Section titled “See individual occurrences”Listing returns the series as one event by default. Pass expand=true with a time window to get per-occurrence instances:
curl "https://api.chronary.ai/v1/calendars/cal_x1y2z3/events?expand=true&start_after=2026-04-01T00:00:00Z&start_before=2026-04-30T23:59:59Z" \ -H "Authorization: Bearer chr_sk_your_key_here"Instances share the master’s id and carry recurringEventId and originalStartTime so you can tell them apart. Availability queries automatically treat every occurrence as busy.
Cancel or modify one occurrence
Section titled “Cancel or modify one occurrence”Cancel a single occurrence by passing its start time to DELETE — the rest of the series is untouched:
curl -X DELETE "https://api.chronary.ai/v1/calendars/cal_x1y2z3/events/evt_m1n2o3?occurrence_start=2026-04-20T09:00:00Z" \ -H "Authorization: Bearer chr_sk_your_key_here"# 200 OK — returns the updated series masterA bare DELETE (no occurrence_start) cancels the whole series. To reschedule one occurrence, cancel it and create a standalone event at the new time.
PATCH always edits the full series — changing times, the rule, or setting recurrence_rule: null (which converts it back to a one-off) applies to every occurrence. See the Events API reference for the complete rule grammar and error codes.
External events are read-only
Section titled “External events are read-only”Pagination
Section titled “Pagination”All list endpoints return paginated results:
{ "data": [ ... ], "total": 142, "limit": 50, "offset": 0}To fetch the next page, increment offset by limit:
GET /v1/calendars/cal_x1y2z3/events?limit=50&offset=50The maximum limit is 200. The default is 50.
Common errors
Section titled “Common errors”| Status | Code | Cause |
|---|---|---|
400 | invalid_time_format | start_time or end_time is not valid ISO 8601 |
400 | end_before_start | end_time is earlier than start_time |
403 | external_event_readonly | Attempted to edit/delete an event with source: "external_ical" |
404 | calendar_not_found | The calendar ID does not exist |
404 | event_not_found | The event ID does not exist on this calendar |
What’s next?
Section titled “What’s next?”- Availability guide — find free time slots based on existing events
- Webhooks guide — get notified when events are created, updated, or deleted
- iCal feeds guide — let humans see agent events in their own calendar apps