# Read a calendar (/build/read-a-calendar)

List the events that fall in a window of time, with each recurring event unfolded into one entry for each time it happens.



A recurring [event](/catalog/event) is one item with a `recurrence` rule, so a listing of items can't say what happens on a given day. [List event occurrences](/api-reference/items/listOccurrences) can: Marfa works out each time an event happens when you ask, and stores none of them. A [task](/catalog/task) can carry the same rule, which Marfa checks on a write and stores, but **never unfolds**: the listing answers events only. In the TypeScript example, `marfa` is a client made as [the TypeScript SDK](/typescript-sdk#create-a-client) shows.

## List a window [#list-a-window]

Name the start and end of the window:



**CLI**

```bash  
marfa items occurrences --from 2026-10-12 --to 2026-10-26
```

**HTTP**

```http
GET /occurrences?from=2026-10-12&to=2026-10-26
Authorization: Bearer <key>
```

**TypeScript**

```ts
const { data } = await marfa.GET("/occurrences", {
  params: { query: { from: "2026-10-12", to: "2026-10-26" } },
});
```

Each entry has a `starts_at`, an `ends_at` where the event has one, and the `item`. An occurrence of a recurring event also carries a `series_id`, the `id` of the `core.event` whose `recurrence` rule made it:

```json
{
  "starts_at": "2026-10-13T07:00:00.000Z",
  "ends_at": "2026-10-13T08:00:00.000Z",
  "series_id": "01a12313-ad0e-71cd-99b4-7a176c5a9f18"
}
```

The whole window comes in one page, in order of `starts_at`.

## Write the bounds [#write-the-bounds]

Marfa reads a bound as it reads any other time you send: a time with no zone, such as `2026-10-12T09:00:00`, is UTC, a date with no time is its midnight in UTC, and an offset or `Z` is honored. A bound that isn't an ISO 8601 time, or names a date that doesn't exist such as `2026-02-30`, is refused with `400 validation_error`, and `details.field` says whether it was `from` or `to`.

A window spans at most **400 days**, and Marfa refuses one with too many occurrences rather than trim it, so narrow the window.

## Check the calendar is whole [#check-the-calendar-is-whole]

If the answer carries `expansion_incomplete: true`, **the calendar is missing something**: `series_errors` names the series that couldn't be unfolded. Show the person that the calendar is incomplete rather than present it as whole.

The rules behind this guide are in the [occurrences](https://github.com/withmarfa/marfa/blob/main/conformance/spec/occurrences.md) chapter of the contract.
