# Calendar feeds

5 endpoints.

## List calendar feeds

```http
GET https://orbitwrite.com/api/v1/calendar-feeds
```

The caller's own feeds (with their tokens), plus — for anyone holding `calendarFeed:manageAny` (owner/admin) — a token-less roster of every feed in the workspace so they can see who created what and revoke if needed.

**Authentication:** session cookie.

### Query parameters

- `organizationId` (string, required)

### Responses

#### 200

The caller's feeds and (for managers) the workspace roster

- `subscriptions` (CalendarFeed[], required)
  - `id` (string, required)
  - `name` (string | null, required)
  - `token` (string, required) — The feed's URL secret — only ever returned to its owner
  - `statuses` (string[], required)
  - `lastAccessedAt` (string | null, required) — ISO 8601.
  - `createdAt` (string, required) — ISO 8601.
- `canManageAll` (boolean, required) — Whether the caller holds `calendarFeed:manageAny` — i.e. may see the roster below and revoke a teammate's feed
- `allSubscriptions` (WorkspaceCalendarFeed[], required) — Roster of every feed in the workspace (token-less); empty unless `canManageAll`
  - `id` (string, required)
  - `name` (string | null, required)
  - `statuses` (string[], required)
  - `lastAccessedAt` (string | null, required) — ISO 8601.
  - `createdAt` (string, required) — ISO 8601.
  - `ownerId` (string, required)
  - `ownerName` (string | null, required)
  - `ownerEmail` (string, required)

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

## Create a calendar feed

```http
POST https://orbitwrite.com/api/v1/calendar-feeds
```

Any member can create feeds for themselves. The response includes the feed's token (its URL secret).

**Authentication:** session cookie.

### Request body (`application/json`)

- `organizationId` (string, required)
- `name` (string, optional)
- `statuses` (string[], optional) — Statuses the feed surfaces. An unknown status is rejected rather than dropped; an empty list means the default view (scheduled + published).

### Responses

#### 200

The feed was created

- `ok` (boolean, required, one of `true`)
- `subscription` (CalendarFeed, required)
  - `id` (string, required)
  - `name` (string | null, required)
  - `token` (string, required) — The feed's URL secret — only ever returned to its owner
  - `statuses` (string[], required)
  - `lastAccessedAt` (string | null, required) — ISO 8601.
  - `createdAt` (string, required) — ISO 8601.

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

## Update one of your calendar feeds

```http
PATCH https://orbitwrite.com/api/v1/calendar-feeds/{feedId}
```

Partial update scoped to the caller's own feeds — an omitted field is left unchanged. Deliberately not widened by `calendarFeed:manageAny`: revoking a teammate's feed is a security action, rewriting their private calendar view is not.

**Authentication:** session cookie.

### Path parameters

- `feedId` (string, required)

### Request body (`application/json`)

- `organizationId` (string, required)
- `name` (string, optional) — The feed's label. Omit to leave it unchanged; send "" to clear it.
- `statuses` (string[], optional) — Statuses the feed surfaces. Omit to leave the current filter unchanged; an empty list means the default view (scheduled + published). An unknown status is rejected rather than dropped.

### Responses

#### 200

The updated feed

- `ok` (boolean, required, one of `true`)
- `subscription` (CalendarFeed, required)
  - `id` (string, required)
  - `name` (string | null, required)
  - `token` (string, required) — The feed's URL secret — only ever returned to its owner
  - `statuses` (string[], required)
  - `lastAccessedAt` (string | null, required) — ISO 8601.
  - `createdAt` (string, required) — ISO 8601.

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

#### 404

The resource does not exist

- `error` (string, required)
- `issues` (any[], optional)

## Revoke a calendar feed

```http
DELETE https://orbitwrite.com/api/v1/calendar-feeds/{feedId}
```

Members revoke their own feeds; anyone holding `calendarFeed:manageAny` (owner/admin) can revoke any feed in the workspace. After this the token 404s.

**Authentication:** session cookie.

### Path parameters

- `feedId` (string, required)

### Query parameters

- `organizationId` (string, required)

### Responses

#### 200

The mutation was applied

- `ok` (boolean, required, one of `true`)

#### 400

Invalid request

- `error` (string, required)
- `issues` (any[], optional)

#### 401

Not signed in

- `error` (string, required)
- `issues` (any[], optional)

#### 403

Not a member of the organization

- `error` (string, required)
- `issues` (any[], optional)

#### 404

The resource does not exist

- `error` (string, required)
- `issues` (any[], optional)

## Public iCal feed

```http
GET https://orbitwrite.com/api/v1/calendar/{token}
```

The iCalendar (.ics) feed behind a calendar-feed subscription. The token is the only credential — no session or API key — so calendar clients can poll it anonymously. A `.ics` suffix on the token is accepted and ignored.

### Path parameters

- `token` (string, required)

### Responses

#### 200

The feed's events as an iCalendar document

#### 404

The resource does not exist

- `error` (string, required)
- `issues` (any[], optional)
