Search the docs
Find a page, a section, or an endpoint.
Recurring events
A rule rather than rows, and what changing one date means.
A repeating event is one row and a rule. Put an RRULE on it and the dates
are expanded when something asks for them.
{
"title": "Standup",
"start": "2026-11-03T09:00:00",
"end": "2026-11-03T09:15:00",
"timezone": "Europe/London",
"recurrence": { "rule": "FREQ=WEEKLY;BYDAY=TU" }
}The rule is RFC 5545's, the same one every calendar speaks. It comes back normalised, so what you read may not be character-for-character what you sent.
It repeats in wall-clock time. A weekly meeting at 09:00 in London is 09:00 in London in November and in June, across the clock change in between. That is why the event stores a wall time and a zone rather than an instant — adding seven days of milliseconds would drift it an hour twice a year.
Most dates have no row
The series is stored; its dates are not. That is what makes a meeting that runs for three years cheap, and it is why there is an endpoint for asking which dates a rule actually produces:
curl "https://pidgeon.ai/api/v1/identities/idn_4f2a1/calendar/events/evt_8c21/instances?after=2026-11-01T00:00:00Z&before=2026-12-01T00:00:00Z" \
-H "Authorization: Bearer $PIDGEON_API_KEY"An instance's id is {seriesId}::{originalStart} — derived from the date
rather than allocated. It does not change when that date is edited, which an
id minted the first time somebody touched it could not promise.
The agenda expands series too, so you rarely need this directly. Reach for it when you want the dates themselves rather than what is on a day.
Changing one date, or the rest of them
A write against a series takes mode, and the id you name is a date, not
the series.
mode | What it means |
|---|---|
single (default) | That date, and only that one |
future | That date and everything after it |
There is no all, and the absence is deliberate: naming the series id
rather than an instance id already means the whole thing, so a third value
would be a second way to say something the API can already say.
PATCH /v1/identities/{id}/calendar/events/{seriesId}::{originalStart}?mode=singlefuture splits the series: the rule is truncated at that date and a new
series starts there carrying the change. A weekly meeting moved four times is
five series, for ever, which is the cost of being able to say "from here on"
without rewriting history.
Deleting one date
DELETE with mode=single does not remove a row — there was no row. It
writes an exception date onto the rule, because a rule with nothing else
done to it would simply generate that date again the next time anybody asked.
You can see them: recurrence.exdates holds the dates that have been taken
out, and rdates holds any added to the series that the rule does not
produce.