> ## Documentation Index
> Fetch the complete documentation index at: https://docs.thefaithapp.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Connected Calendars

> Authorize Google or Outlook calendars and synchronize church schedules and member serving responses.

The connected-calendar API uses Composio-hosted OAuth links. Provider tokens
stay with Composio. TheFaithApp stores encrypted connected-account metadata
and tenant-bound mappings rather than accepting provider account IDs from
the client.

## Routes and Ownership

Staff routes use a staff bearer token:

* `/api/events/calendar-connections` manages the church organizer connection
  and requires Events permission.
* `/api/volunteer/calendar-connections` manages the authenticated staff
  member's own calendar. The staff email must be verified and match a member
  record in the same church.

Member routes use the authenticated member session:

* `/api/member/calendar-connections`
* `/v2/volunteer/calendar-connections`

Each route family supports:

| Method and suffix | Purpose |
| - | - |
| `GET /` | List owned connections, provider availability, run history, and own assignments |
| `POST /` | Start or reconnect with `provider: google` or `provider: outlook` |
| `POST /{uuid}/refresh` | Verify OAuth completion and the expected provider, auth configuration, and user |
| `GET /{uuid}/calendars` | List accessible calendars and whether they can be edited |
| `PUT /{uuid}` | Choose `calendar_id`, `include_events`, and `include_serving` |
| `POST /{uuid}/retry` | Queue a sync after a calendar is selected |
| `DELETE /{uuid}` | Revoke upstream authorization and stop future synchronization |

Member route families also support
`POST /assignments/{uuid}/respond` with `response: confirmed` or
`response: declined`. A decline requires `reason`. The assignment must belong
to that member and church.

## Synchronization Contract

TheFaithApp remains the schedule source. Registered member events and eligible
published serving assignments are mirrored to the selected member calendar.
Church connections mirror published events and serving plans. Internal notes,
safeguarding data, and unrelated calendars are excluded.

Stable mappings update an existing provider event when times or locations
change, and remove only mapped events after cancellation. Provider event
creation uses deterministic IDs or transaction identifiers to avoid duplicate
creates after an ambiguous response. Timezones are included explicitly.

For native serving RSVPs, a church organizer connection and the member's
active, opted-in serving connection must use the same provider. The member's
verified connected account email is the attendee. Only the mapped organizer
event's response for that attendee can change the assignment. A copied
personal appointment uses a TheFaithApp response link instead; deleting or
editing it is not an RSVP.

Sync is queued after relevant changes and polled by the scheduler. Provider
limits and authorization failures appear in connection status and run history.
Run the queue worker and Laravel scheduler for synchronization to continue.
Disconnect immediately stops local synchronization, attempts to delete mapped
provider entries, and revokes upstream access. Failed cleanup can leave entries
in the provider and is shown in connection status. Switching a selected calendar
removes its mapped entries before creating the new set.

## Calendar Response Links

Personal appointment copies include a temporary signed response link to the
Next.js frontend at
`/calendar/serving-response/{connectionUuid}/{assignmentUuid}`. The page shows
assignment details and records a response only after an explicit form submit.
It requires no staff login. The frontend calls the calendar response API from
the server; provider tokens and staff credentials are not sent to the page.

The API supports `GET` and `POST` at
`/api/calendar/serving-response/{connectionUuid}/{assignmentUuid}`. Both require
the original query string, in this order:
`expires=<unix timestamp>&signature=<64 lowercase hexadecimal characters>`.
The signature covers the relative API path and expiry. Extra or duplicate
query parameters are rejected. The signed link authorizes only that assignment
in the connection's church; client and member selectors are not accepted.

`GET` returns `success: true` and a `data` object containing `title`, `role`,
`starts_at`, `ends_at`, `timezone`, `location`, `status`, `saved`, and
`can_respond`. Timestamps are UTC ISO values with the plan's IANA timezone
provided for display; timestamps and location may be null. GET has no response
side effects and returns `saved: false`.

`POST` accepts JSON:

```json theme={null}
{
  "response": "declined",
  "reason": "I am unavailable on that date."
}
```

Use `confirmed` to accept or `declined` to decline. A decline requires a reason
of at most 2,000 characters. A successful POST returns the same data contract
with `saved: true`. A confirmed assignment may be declined later. Declined
assignments return `can_respond: false`; changing one back to confirmed returns
HTTP 409. Repeated responses use the existing assignment response service.

Invalid or expired signatures return HTTP 403. Revoked connections, mismatched
ownership, or assignments no longer available return HTTP 404. Validation
errors return HTTP 422; the per-capability rate limit returns HTTP 429. Private
responses and redirects use `no-store`, `no-referrer`, and `noindex` headers.

Existing absolute signed links on the API host at
`/calendar/serving-response/{connectionUuid}/{assignmentUuid}` remain valid until
their original expiry. GET validates the old link and redirects to the frontend
with a new relative API signature **without extending that expiry**. The legacy
POST remains CSRF-protected and returns JSON. Laravel no longer renders the
member response page.

Treat each link as a private bearer capability: anyone who receives it can
respond for that assignment. It becomes invalid when its connection is revoked.
Keep signed URLs and decline reasons out of logs, analytics, and error reports;
application telemetry suppresses these fields, but proxy and access-log query
retention must also be configured by the deployment operator.

## Deployment

Configure server-only `COMPOSIO_API_KEY`,
`COMPOSIO_GOOGLE_CALENDAR_AUTH_CONFIG_ID`, and
`COMPOSIO_OUTLOOK_AUTH_CONFIG_ID`. Optional `COMPOSIO_BASE_URL` defaults to
Composio's API host. Staff OAuth redirects use `DASHBOARD_URL`; member redirects
use the trusted TheFaithApp app link back to the Volunteer Hub. Set
`FRONTEND_URL` to the installation's HTTPS Next.js origin for serving response
links, and `APP_URL` to the correct API origin for existing absolute signatures.
Deploy the frontend page and JSON API together before testing new or legacy
calendar response links.

For Google, calendar-list read access and event read/write access are required.
For Outlook, use calendar read/write and account profile access with refresh
authorization. Grant actual provider data access only through the end user's
OAuth consent flow. Providers with missing configuration are unavailable in
the dashboard.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.