# AddCal API Documentation

The official AddCal API documentation. This comprehensive guide provides developers with everything needed to integrate calendar and event management functionality into their applications. Our RESTful API enables seamless creation, management, and sharing of events across multiple platforms and calendar services.

- Base URL: `https://addcal.co`
- Authentication: HTTP Bearer token. You can retrieve your token from the [API Tokens page](https://addcal.co/user/api-tokens) in your dashboard.
- OpenAPI document: https://addcal.co/docs.openapi
- Interactive reference: https://addcal.co/docs

Send the token on every request:

```
Authorization: Bearer YOUR_API_TOKEN
Accept: application/json
```

## Sections

- [Create Event](https://addcal.co/docs/create-event.md)
- [Calendars](https://addcal.co/docs/calendars.md)
- [Calendars > Subscribers](https://addcal.co/docs/subscribers.md)
- [Events](https://addcal.co/docs/events.md)
- [Events > RSVPs](https://addcal.co/docs/rsvps.md)
- [Events > Invites](https://addcal.co/docs/invites.md)
- [Account](https://addcal.co/docs/account.md)
- [Dynamic Links](https://addcal.co/docs/dynamic-links.md)
- [Endpoints](https://addcal.co/docs/endpoints.md)

## Create Event

A simplified endpoint for creating events with smart defaults and automatic calendar management.

This endpoint provides a streamlined way to create events by handling calendar creation and management automatically. It offers three ways to specify a calendar:
1. Use an existing calendar by providing its `calendar_uid`
2. Create or reuse a calendar by name using `calendar_name`
3. Use a default calendar (automatically created if needed)

Key features:
- Automatic 1-hour duration if no end time is specified
- Flexible team selection with smart defaults
- Automatic calendar creation with sensible defaults
- Timezone inheritance from calendar if not specified
- Support for all-day events

The response includes the created event details along with calendar information and add-to-calendar links for various platforms.

### /api/events

`POST /api/events`

**Query parameters**

- `with_html` (boolean, optional): Include HTML variants for calendar links in the response

**Body parameters** (`application/json`)

- `title` (string, required): The title of the event. Must not be greater than 255 characters.
- `description` (string, optional): A detailed description of the event.
- `location` (string, optional): The location where the event will take place. Must not be greater than 255 characters.
- `is_all_day` (boolean, optional): Whether this is an all-day event.
- `is_virtual` (boolean, optional): Whether this is a virtual/online event.
- `organiser_name` (string, optional): The name of the event organiser. Must not be greater than 255 characters.
- `organiser_email` (string, optional): The email address of the event organiser. Must be a valid email address. Must not be greater than 191 characters.
- `recurrence_rule` (string, optional): iCalendar RRULE string for recurring events (e.g. FREQ=DAILY;INTERVAL=1;COUNT=3).
- `series_title` (string, optional): Title for the recurring event series. Defaults to the event title if not provided. Must not be greater than 255 characters.
- `has_rsvp` (boolean, optional): Whether this event allows RSVP responses.
- `date_start` (string, required): The start date and time of the event. Must be a valid date.
- `date_end` (string, required): The end date and time of the event. If not provided, defaults to 1 hour after start time. Must be a valid date. Must be a date after or equal to date_start.
- `timezone` (string, optional): The timezone for the event. Defaults to calendar timezone if not provided. Must be a valid time zone, such as Africa/Accra.
- `busy_type` (string, optional): Whether the event shows as busy or free on calendars. Options: busy, or free, calendar default when null. Options: `busy`, `free`.
- `reminder_before` (integer, optional): Minutes before the event to send a notification. Common values: 0, 5, 10, 15, 30, 60, 120, 1440 (1 day), etc. Must be at least 0.
- `short_link` (string, optional): Custom short link for the event. Only available for subscribers. Must match the regex /^[a-zA-Z0-9-]+$/. Must not be greater than 50 characters.
- `team_uid` (string, optional): The unique identifier of the team to create the event for. Defaults to current team or first available team.
- `calendar_uid` (string, optional): The unique identifier of an existing calendar to create the event in.
- `calendar_name` (string, optional): Name of the calendar to create or use. Cannot be used with calendar_uid. Must not be greater than 255 characters.

**Example request**

```bash
curl --request POST \
  --url 'https://addcal.co/api/events' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
    "title": "Team Meeting",
    "description": "Monthly team sync to discuss project progress and upcoming milestones.",
    "location": "Conference Room A or https://zoom.us/j/123456789",
    "is_all_day": false,
    "is_virtual": false,
    "organiser_name": "Jane Smith",
    "organiser_email": "jane@example.com",
    "recurrence_rule": "FREQ=WEEKLY;BYDAY=MO;COUNT=10",
    "series_title": "Weekly Team Meeting",
    "has_rsvp": false,
    "date_start": "2024-03-25 14:00:00",
    "date_end": "2024-03-25 15:00:00",
    "timezone": "America/New_York",
    "busy_type": "busy",
    "reminder_before": 30,
    "short_link": "my-event",
    "team_uid": "team_abc123",
    "calendar_uid": "cal_xyz789",
    "calendar_name": "Team Meetings"
}'
```

**Response 200**

```json
{
    "data": {
        "uid": "rkpp3x41r8ih",
        "public_id": "evt_rkpp3x41r8ih",
        "calendar_uid": "cal_m9aokdxfmnhh",
        "short_link": null,
        "title": "Ut sequi magni vel dolorem id deleniti quia.",
        "internal_name": null,
        "is_draft": false,
        "description": "<p>Omnis beatae accusantium et quasi et. Quo aliquam quaerat qui in officiis omnis aliquam eaque. Aut sunt veritatis quis explicabo quidem doloremque. Aliquam aut consequuntur fuga exercitationem pariatur explicabo.</p>\n\n<p>Quia officiis asperiores debitis natus excepturi. Perspiciatis autem aut id provident. Voluptatum nesciunt optio reiciendis molestiae. Veritatis ut qui sed ea quisquam necessitatibus.</p>",
        "location": "285 Cassie Summit\nGottliebville, MO 30606",
        "is_all_day": false,
        "has_rsvp": false,
        "has_calendar_invites": false,
        "rsvp_limit": null,
        "is_recurring": false,
        "recurrence_rule": null,
        "recurrence_text": null,
        "date_start": "2026-09-06T02:01:00-05:00",
        "date_end": "2026-09-06T03:01:00-05:00",
        "timezone": "America/Chicago",
        "busy_type": null,
        "reminder_before": null,
        "date_range_formatted": "Sun, Sep 6, 2026 2:01 AM - 3:01 AM",
        "public_url": "http://addcal.co/e/rkpp3x41r8ih",
        "embed_url": "http://addcal.co/e/rkpp3x41r8ih",
        "location_url": null,
        "image_url": null,
        "timezone_readable": "CDT / GMT-05:00",
        "calendar": {
            "uid": "m9aokdxfmnhh",
            "public_id": "cal_m9aokdxfmnhh",
            "short_link": null,
            "name": "et alias optio",
            "internal_name": null,
            "description": "<p>Impedit mollitia corrupti corrupti repellat. Quia sunt distinctio illum voluptatum. Qui et esse voluptates pariatur.</p>",
            "timezone": "America/Campo_Grande",
            "week_begins": 6,
            "public_url": "http://addcal.co/c/m9aokdxfmnhh",
            "created_at": "2026-08-28T03:20:12.000000Z",
            "updated_at": "2026-08-28T03:20:12.000000Z"
        },
        "created_at": "2026-08-28T03:20:12.000000Z",
        "updated_at": "2026-08-28T03:20:12.000000Z"
    },
    "links": {
        "event_page": "http://addcal.co/e/rkpp3x41r8ih",
        "auto": "https://addcal.co/e/rkpp3x41r8ih/auto",
        "google": "https://addcal.co/e/rkpp3x41r8ih/google",
        "apple": "https://addcal.co/e/rkpp3x41r8ih/apple",
        "outlook": "https://addcal.co/e/rkpp3x41r8ih/outlook",
        "outlook_web": "https://addcal.co/e/rkpp3x41r8ih/outlook_web",
        "yahoo": "https://addcal.co/e/rkpp3x41r8ih/yahoo",
        "office365": "https://addcal.co/e/rkpp3x41r8ih/office365",
        "ics": "https://addcal.co/e/rkpp3x41r8ih/ics"
    },
    "html": {
        "single-button": "Add to Calendar Button",
        "icon-buttons-single-row": "Buttons With Icons",
        "icons": "Text with Icons",
        "dot-sep": "Text (dot separated)",
        "space-sep": "Text (space separated)"
    }
}
```

**Response 409** — When the team's event limit has been exceeded

```json
{
    "message": "You have reached your monthly event limit of 10. Please upgrade your plan to create more events.",
    "current": 10,
    "limit": 10,
    "remaining": 0,
    "would_exceed_by": 1,
    "is_unlimited": false,
    "limit_type": "monthly"
}
```

## Calendars

APIs for managing calendars

### List Calendars

`GET /api/calendars`

**Example request**

```bash
curl --request GET \
  --url 'https://addcal.co/api/calendars' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

**Response 200**

```json
{
    "data": [
        {
            "uid": "p9v02qsz079d",
            "public_id": "cal_p9v02qsz079d",
            "short_link": null,
            "name": "Test RSVP Cal",
            "internal_name": null,
            "description": "",
            "timezone": "Australia/Adelaide",
            "week_begins": 4,
            "public_url": "https://addcal.co/c/p9v02qsz079d",
            "upcoming_events_count": 2,
            "events_count": 72,
            "created_at": "2025-07-27T06:43:09.000000Z",
            "updated_at": "2025-11-18T03:43:23.000000Z"
        },
        {
            "uid": "0vwbr1bxbjai",
            "public_id": "cal_0vwbr1bxbjai",
            "short_link": null,
            "name": "Test User's Calendar",
            "internal_name": null,
            "description": "<p>Professional meetings, webinars, and business events.</p>",
            "timezone": "Australia/Sydney",
            "week_begins": 1,
            "public_url": "https://addcal.co/c/0vwbr1bxbjai",
            "upcoming_events_count": 6,
            "events_count": 8,
            "created_at": "2025-07-29T23:32:49.000000Z",
            "updated_at": "2025-07-29T23:32:49.000000Z"
        },
        {
            "uid": "moexypnt3wd4",
            "public_id": "cal_moexypnt3wd4",
            "short_link": null,
            "name": "Test User's Calendar",
            "internal_name": null,
            "description": "<p>Professional meetings, webinars, and business events.</p>",
            "timezone": "Australia/Sydney",
            "week_begins": 1,
            "public_url": "https://addcal.co/c/moexypnt3wd4",
            "upcoming_events_count": 0,
            "events_count": 0,
            "created_at": "2025-07-29T23:34:05.000000Z",
            "updated_at": "2025-07-29T23:34:05.000000Z"
        },
        {
            "uid": "gvjtfhquosip",
            "public_id": "cal_gvjtfhquosip",
            "short_link": null,
            "name": "Test User's Calendar",
            "internal_name": null,
            "description": "<p>Personal events, family gatherings, and appointments.</p>",
            "timezone": "Australia/Sydney",
            "week_begins": 1,
            "public_url": "https://addcal.co/c/gvjtfhquosip",
            "upcoming_events_count": 0,
            "events_count": 252,
            "created_at": "2025-07-29T23:37:16.000000Z",
            "updated_at": "2025-07-29T23:37:16.000000Z"
        },
        {
            "uid": "yxlbclyhg4e7",
            "public_id": "cal_yxlbclyhg4e7",
            "short_link": null,
            "name": "Test User's  Tags",
            "internal_name": null,
            "description": "<p>Professional meetings, webinars, and business events.</p>",
            "timezone": "Australia/Sydney",
            "week_begins": 1,
            "public_url": "https://addcal.co/c/yxlbclyhg4e7",
            "upcoming_events_count": 0,
            "events_count": 13,
            "created_at": "2025-07-29T23:43:37.000000Z",
            "updated_at": "2025-08-23T05:25:01.000000Z"
        },
        {
            "uid": "vj0wmxp7fo66",
            "public_id": "cal_vj0wmxp7fo66",
            "short_link": "test-cal",
            "name": "Recur test",
            "internal_name": null,
            "description": "",
            "timezone": "Australia/Sydney",
            "week_begins": 1,
            "public_url": "https://addcal.co/c/test-cal",
            "upcoming_events_count": 0,
            "events_count": 40,
            "created_at": "2025-09-07T00:12:49.000000Z",
            "updated_at": "2026-07-11T02:47:33.000000Z"
        },
        {
            "uid": "irir0ggat1pc",
            "public_id": "cal_irir0ggat1pc",
            "short_link": null,
            "name": "Series",
            "internal_name": null,
            "description": "",
            "timezone": "Australia/Sydney",
            "week_begins": 1,
            "public_url": "https://addcal.co/c/irir0ggat1pc",
            "upcoming_events_count": 0,
            "events_count": 30,
            "created_at": "2025-09-17T02:17:41.000000Z",
            "updated_at": "2025-09-17T02:17:41.000000Z"
        },
        {
            "uid": "vdp2pp652p6z",
            "public_id": "cal_vdp2pp652p6z",
            "short_link": null,
            "name": "Tag Filter Demo",
            "internal_name": null,
            "description": "<p>Seeded calendar for testing tag-filtered subscriptions.</p>",
            "timezone": "UTC",
            "week_begins": 1,
            "public_url": "https://addcal.co/c/vdp2pp652p6z",
            "upcoming_events_count": 0,
            "events_count": 9,
            "created_at": "2026-07-29T01:28:22.000000Z",
            "updated_at": "2026-07-31T04:22:27.000000Z"
        },
        {
            "uid": "o5mn1flqqxo7",
            "public_id": "cal_o5mn1flqqxo7",
            "short_link": null,
            "name": "Tag Filter Demo (Require Info)",
            "internal_name": null,
            "description": "<p>Same tags, but gated behind the subscriber info form.</p>",
            "timezone": "UTC",
            "week_begins": 1,
            "public_url": "https://addcal.co/c/o5mn1flqqxo7",
            "upcoming_events_count": 0,
            "events_count": 3,
            "created_at": "2026-07-29T01:28:22.000000Z",
            "updated_at": "2026-07-29T02:49:17.000000Z"
        },
        {
            "uid": "qr0d313df3vs",
            "public_id": "cal_qr0d313df3vs",
            "short_link": null,
            "name": "Tag Filter Demo (Opted Out)",
            "internal_name": null,
            "description": "<p>Tags exist but allow_tag_selection is off - control case.</p>",
            "timezone": "UTC",
            "week_begins": 1,
            "public_url": "https://addcal.co/c/qr0d313df3vs",
            "upcoming_events_count": 0,
            "events_count": 2,
            "created_at": "2026-07-29T01:28:22.000000Z",
            "updated_at": "2026-07-29T01:28:22.000000Z"
        },
        {
            "uid": "4t0x0n0q6hvt",
            "public_id": "cal_4t0x0n0q6hvt",
            "short_link": null,
            "name": "vitae blanditiis rerum",
            "internal_name": "saepe eius ut",
            "description": "<p>Repudiandae quos suscipit similique saepe maiores. Omnis officiis qui placeat voluptates. Quia sunt corporis quis quasi harum in odio.</p>",
            "timezone": "UTC",
            "week_begins": 5,
            "public_url": "https://addcal.co/c/4t0x0n0q6hvt",
            "upcoming_events_count": 0,
            "events_count": 2,
            "created_at": "2026-07-31T06:19:21.000000Z",
            "updated_at": "2026-07-31T06:19:21.000000Z"
        },
        {
            "uid": "hsr6p96ex40w",
            "public_id": "cal_hsr6p96ex40w",
            "short_link": null,
            "name": "rem quia maxime",
            "internal_name": null,
            "description": "<p>Cum optio dolor ducimus vitae enim. Consequatur perferendis velit non cum. Accusamus aut quidem dicta et numquam.</p>",
            "timezone": "UTC",
            "week_begins": 4,
            "public_url": "https://addcal.co/c/hsr6p96ex40w",
            "upcoming_events_count": 2,
            "events_count": 4,
            "created_at": "2026-07-31T06:25:45.000000Z",
            "updated_at": "2026-07-31T06:25:45.000000Z"
        },
        {
            "uid": "w4beoawsjlzh",
            "public_id": "cal_w4beoawsjlzh",
            "short_link": null,
            "name": "magnam perspiciatis nesciunt",
            "internal_name": null,
            "description": "<p>Est quam commodi excepturi possimus. Expedita totam vel perferendis nesciunt est accusamus. Fugiat recusandae ipsam ducimus repudiandae. Possimus qui et tempore quasi architecto repellat.</p>",
            "timezone": "UTC",
            "week_begins": 4,
            "public_url": "https://addcal.co/c/w4beoawsjlzh",
            "upcoming_events_count": 2,
            "events_count": 4,
            "created_at": "2026-07-31T06:25:45.000000Z",
            "updated_at": "2026-07-31T06:25:45.000000Z"
        },
        {
            "uid": "z9s82mzzyz9h",
            "public_id": "cal_z9s82mzzyz9h",
            "short_link": null,
            "name": "ut culpa doloribus",
            "internal_name": null,
            "description": "<p>Esse in voluptatem error delectus. Nesciunt delectus qui perferendis praesentium nihil tenetur. Eum sequi aut voluptatibus.</p>",
            "timezone": "UTC",
            "week_begins": 2,
            "public_url": "https://addcal.co/c/z9s82mzzyz9h",
            "upcoming_events_count": 2,
            "events_count": 4,
            "created_at": "2026-07-31T06:25:45.000000Z",
            "updated_at": "2026-07-31T06:25:45.000000Z"
        },
        {
            "uid": "zn7jthtmcu6v",
            "public_id": "cal_zn7jthtmcu6v",
            "short_link": null,
            "name": "blanditiis qui similique",
            "internal_name": null,
            "description": "",
            "timezone": "UTC",
            "week_begins": 3,
            "public_url": "https://addcal.co/c/zn7jthtmcu6v",
            "upcoming_events_count": 5,
            "events_count": 12,
            "created_at": "2026-07-31T06:25:45.000000Z",
            "updated_at": "2026-07-31T06:25:45.000000Z"
        },
        {
            "uid": "53shwnly2hec",
            "public_id": "cal_53shwnly2hec",
            "short_link": null,
            "name": "mollitia est sunt",
            "internal_name": null,
            "description": "",
            "timezone": "UTC",
            "week_begins": 6,
            "public_url": "https://addcal.co/c/53shwnly2hec",
            "upcoming_events_count": 2,
            "events_count": 4,
            "created_at": "2026-07-31T06:30:17.000000Z",
            "updated_at": "2026-07-31T06:30:17.000000Z"
        },
        {
            "uid": "dtm5tai0heff",
            "public_id": "cal_dtm5tai0heff",
            "short_link": null,
            "name": "sit delectus aliquam",
            "internal_name": "ea sed esse",
            "description": "",
            "timezone": "UTC",
            "week_begins": 3,
            "public_url": "https://addcal.co/c/dtm5tai0heff",
            "upcoming_events_count": 2,
            "events_count": 4,
            "created_at": "2026-07-31T06:30:17.000000Z",
            "updated_at": "2026-07-31T06:30:17.000000Z"
        },
        {
            "uid": "8lkpjn1v9478",
            "public_id": "cal_8lkpjn1v9478",
            "short_link": null,
            "name": "eveniet a nulla",
            "internal_name": "velit provident aperiam",
            "description": "",
            "timezone": "UTC",
            "week_begins": 2,
            "public_url": "https://addcal.co/c/8lkpjn1v9478",
            "upcoming_events_count": 2,
            "events_count": 24,
            "created_at": "2026-07-31T06:30:17.000000Z",
            "updated_at": "2026-07-31T06:30:17.000000Z"
        },
        {
            "uid": "ffyq1eyfpzn4",
            "public_id": "cal_ffyq1eyfpzn4",
            "short_link": null,
            "name": "Wedding",
            "internal_name": null,
            "description": "",
            "timezone": "Australia/Sydney",
            "week_begins": 1,
            "public_url": "https://addcal.co/c/ffyq1eyfpzn4",
            "upcoming_events_count": 1,
            "events_count": 1,
            "created_at": "2026-08-13T02:53:56.000000Z",
            "updated_at": "2026-08-13T02:53:56.000000Z"
        },
        {
            "uid": "4vym88ak6pnj",
            "public_id": "cal_4vym88ak6pnj",
            "short_link": null,
            "name": "Default Calendar",
            "internal_name": null,
            "description": "",
            "timezone": "Australia/Sydney",
            "week_begins": 1,
            "public_url": "https://addcal.co/c/4vym88ak6pnj",
            "upcoming_events_count": 0,
            "events_count": 4,
            "created_at": "2026-08-16T09:50:40.000000Z",
            "updated_at": "2026-08-16T09:50:40.000000Z"
        },
        {
            "uid": "77r9qzpie5xw",
            "public_id": "cal_77r9qzpie5xw",
            "short_link": null,
            "name": "Imported Events",
            "internal_name": null,
            "description": "<p>Events imported from your public event creations.</p>",
            "timezone": "Australia/Sydney",
            "week_begins": 1,
            "public_url": "https://addcal.co/c/77r9qzpie5xw",
            "upcoming_events_count": 0,
            "events_count": 1,
            "created_at": "2026-08-16T21:35:16.000000Z",
            "updated_at": "2026-08-16T21:35:16.000000Z"
        }
    ]
}
```

### Create Calendar

`POST /api/calendars`

**Body parameters** (`application/json`)

- `name` (string, required): Must not be greater than 255 characters.
- `internal_name` (string, optional): Must not be greater than 255 characters.
- `description` (string, optional): Must not be greater than 255 characters.
- `timezone` (string, required): Must be a valid time zone, such as Africa/Accra.
- `week_begins` (integer, required): No description. Options: `1`, `2`, `3`, `4`, `5`, `6`, `0`.

**Example request**

```bash
curl --request POST \
  --url 'https://addcal.co/api/calendars' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
    "name": "zxplduayr",
    "internal_name": "rjzj",
    "description": "Non repellendus eligendi impedit aspernatur.",
    "timezone": "Africa/Brazzaville",
    "week_begins": 5
}'
```

**Response 409**

```json
{
    "message": "You have reached your calendar limit. Please upgrade your plan to create more calendars."
}
```

### Get Calendar

`GET /api/calendars/{public_id}`

**Path parameters**

- `public_id` (string, required): The ID of the public.

**Example request**

```bash
curl --request GET \
  --url 'https://addcal.co/api/calendars/{public_id}' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

**Response 200**

```json
{
    "data": {
        "uid": "p9v02qsz079d",
        "public_id": "cal_p9v02qsz079d",
        "short_link": null,
        "name": "Test RSVP Cal",
        "internal_name": null,
        "description": "",
        "timezone": "Australia/Adelaide",
        "week_begins": 4,
        "public_url": "https://addcal.co/c/p9v02qsz079d",
        "upcoming_events_count": 2,
        "events_count": 72,
        "created_at": "2025-07-27T06:43:09.000000Z",
        "updated_at": "2025-11-18T03:43:23.000000Z"
    }
}
```

### Update Calendar

`PUT /api/calendars/{public_id}`

**Path parameters**

- `public_id` (string, required): The ID of the public.

**Body parameters** (`application/json`)

- `name` (string, required): Must not be greater than 255 characters.
- `internal_name` (string, optional): Must not be greater than 255 characters.
- `description` (string, optional): Must not be greater than 255 characters.
- `timezone` (string, required): Must be a valid time zone, such as Africa/Accra.
- `week_begins` (integer, required): No description. Options: `1`, `2`, `3`, `4`, `5`, `6`, `0`.

**Example request**

```bash
curl --request PUT \
  --url 'https://addcal.co/api/calendars/{public_id}' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
    "name": "zsbvmmarvcxzpzneeqrugpwps",
    "internal_name": "xbaazfazbqwyhgqymyux",
    "description": "Voluptatem voluptatem ipsa sequi atque inventore.",
    "timezone": "America/Barbados",
    "week_begins": 5
}'
```

### Delete Calendar

`DELETE /api/calendars/{public_id}`

**Path parameters**

- `public_id` (string, required): The ID of the public.

**Example request**

```bash
curl --request DELETE \
  --url 'https://addcal.co/api/calendars/{public_id}' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

### Generate Signed URL

`POST /api/calendars/{calendar_public_id}/signed-url`

Generate a signed URL for a protected calendar. The URL includes an expiry timestamp and a cryptographic signature, and expires after the specified number of days.

The calendar must have an access code set. If no `expiry_days` is provided, the calendar's configured `signed_url_expiry_days` is used, or 30 days as a default.

The returned URL grants temporary access based on its signature validity, without exposing the access code. It can be shared with users who need time-limited access.

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.

**Body parameters** (`application/json`)

- `expiry_days` (integer, optional): Number of days until the signed URL expires. Min 1, max 365.

**Example request**

```bash
curl --request POST \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/signed-url' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
    "expiry_days": 30
}'
```

**Response 200**

```json
{
    "url": "https://addcal.co/c/cal_abc123?expires=1741000000&signature=abc..."
}
```

**Response 422**

```json
{
    "error": "Calendar does not have an access code set."
}
```

## Calendars > Subscribers

APIs for reading the people who have subscribed to a calendar.

## Matching subscribers to your own records

Pass `external_id` when someone subscribes and that value comes back here, so an AddCal
subscriber can be reconciled against a record in your own system.

Set it on an embed as `data-external-id`, or on a link to a hosted calendar page as
`?external_id=`:

```
<div class="addcal-btn" data-calendar="cal_abc123" data-external-id="member-8412"></div>

https://addcal.co/c/cal_abc123?external_id=member-8412
```

**The subscribe route drops a malformed id silently.** It accepts 1-191 characters matching
`^[A-Za-z0-9._:-]+$`; anything else is discarded and the subscribe still succeeds, with no
error and no field in the response. That is deliberate: the person subscribing is a real
visitor, and an id that only matters to your integration should not fail their subscribe.

The practical consequence is that an email address, a base64 token, or anything over 191
characters will never reach this endpoint, and the first sign of it is a subscriber that
cannot be matched. Validate the shape on your side before you send it. This endpoint does
reject a malformed `external_id` with a 422, so it can be used to check an id's shape.

To find whether one of your records is subscribed, filter by it and check whether the
response contains any rows:

```
GET /api/calendars/cal_abc123/subscribers?external_id=member-8412
```

### List subscribers

`GET /api/calendars/{calendar_public_id}/subscribers`

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.

**Query parameters**

- `external_id` (string, optional): Only return subscribers carrying this external id.
- `per_page` (integer, optional): Number of results per page (1-100)

**Body parameters** (`application/json`)

- `external_id` (string, optional): Must match the regex /^[A-Za-z0-9._:-]+$/. Must not be greater than 191 characters.
- `per_page` (integer, optional): Must be at least 1. Must not be greater than 100.

**Example request**

```bash
curl --request GET \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/subscribers' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

**Response 200**

```json
{
    "data": [
        {
            "uid": "vuh5fsk8wh62wr",
            "public_id": "sub_vuh5fsk8wh62wr",
            "service": "outlook",
            "name": null,
            "email": null,
            "data": null,
            "status": "inactive",
            "created_at": "2026-08-28T03:20:12.000000Z",
            "updated_at": "2026-08-28T03:20:12.000000Z"
        },
        {
            "uid": "d2w829050qqm73",
            "public_id": "sub_d2w829050qqm73",
            "service": "ics",
            "name": null,
            "email": null,
            "data": null,
            "status": "inactive",
            "created_at": "2026-08-28T03:20:12.000000Z",
            "updated_at": "2026-08-28T03:20:12.000000Z"
        }
    ]
}
```

## Events

Advanced APIs for managing events

### Index All Events

`GET /api/events`

**Query parameters**

- `range` (string, optional): Filter events by time range. Options: 'all', 'upcoming', 'past'
- `search` (string, optional): Search events by title or internal name
- `calendar` (string, optional): Filter events by calendar ID
- `start_date` (string, optional): Filter events starting from this date (ISO 8601 format)
- `end_date` (string, optional): Filter events ending before this date (ISO 8601 format)
- `rsvp` (boolean, optional): Only return events with RSVPs enabled (true) or disabled (false)
- `invites` (boolean, optional): Only return events with calendar invites enabled (true) or disabled (false)

**Body parameters** (`application/json`)

- `range` (string, optional): No description. Options: `all`, `upcoming`, `past`.
- `search` (string, optional): Must not be greater than 255 characters.
- `calendar` (string, optional): Must not be greater than 255 characters.
- `start_date` (string, optional): Must be a valid date.
- `end_date` (string, optional): Must be a valid date.
- `rsvp` (string, optional): No description. Options: `1`, `0`, `true`, `false`.
- `invites` (string, optional): No description. Options: `1`, `0`, `true`, `false`.

**Example request**

```bash
curl --request GET \
  --url 'https://addcal.co/api/events' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

**Response 200**

```json
{
    "data": [
        {
            "uid": "2497uth7f3zn",
            "public_id": "evt_2497uth7f3zn",
            "calendar_uid": "cal_eox0hmwyeu5k",
            "short_link": null,
            "title": "Sunt fugit tempore natus ducimus quae ut dolorum.",
            "internal_name": null,
            "is_draft": false,
            "description": "<p>Ducimus aut ab assumenda magnam labore consequuntur. Et est ea harum est et. Suscipit similique numquam incidunt consequatur. In nisi ut eveniet unde rerum est molestiae.</p>\n\n<p>Tenetur odio occaecati dolores. Labore quisquam sequi inventore voluptatem voluptatem totam. Consectetur nihil et possimus deserunt animi magnam dolorem. Et unde tenetur similique nam.</p>",
            "location": "342 Daugherty Mount\nSipesland, NE 37279-0492",
            "is_all_day": false,
            "has_rsvp": false,
            "has_calendar_invites": false,
            "rsvp_limit": null,
            "is_recurring": false,
            "recurrence_rule": null,
            "recurrence_text": null,
            "date_start": "2026-09-18T13:46:51+01:00",
            "date_end": "2026-09-18T16:46:51+01:00",
            "timezone": "Atlantic/Madeira",
            "busy_type": null,
            "reminder_before": null,
            "date_range_formatted": "Fri, Sep 18, 2026 1:46 PM - 4:46 PM",
            "public_url": "http://addcal.co/e/2497uth7f3zn",
            "embed_url": "http://addcal.co/e/2497uth7f3zn",
            "location_url": null,
            "image_url": null,
            "timezone_readable": "WEST / GMT+01:00",
            "calendar": {
                "uid": "eox0hmwyeu5k",
                "public_id": "cal_eox0hmwyeu5k",
                "short_link": null,
                "name": "aut beatae commodi",
                "internal_name": "consequatur sint voluptatem",
                "description": "",
                "timezone": "America/Santarem",
                "week_begins": 4,
                "public_url": "http://addcal.co/c/eox0hmwyeu5k",
                "created_at": "2026-08-28T03:20:12.000000Z",
                "updated_at": "2026-08-28T03:20:12.000000Z"
            },
            "created_at": "2026-08-28T03:20:12.000000Z",
            "updated_at": "2026-08-28T03:20:12.000000Z"
        },
        {
            "uid": "ap3xucsxrxyj",
            "public_id": "evt_ap3xucsxrxyj",
            "calendar_uid": "cal_ndi7c217vncr",
            "short_link": null,
            "title": "Modi esse est consequatur est et quibusdam laborum.",
            "internal_name": null,
            "is_draft": false,
            "description": "<p>Optio eius qui quod ut non. Et porro sapiente earum. Id hic reprehenderit amet nihil quasi.</p>\n\n<p>Provident exercitationem earum illo minus aspernatur ut et. Esse aspernatur sunt rerum rerum reiciendis maiores. Rem in illum est quis.</p>",
            "location": "257 Spinka Forks\nToniberg, SD 00015",
            "is_all_day": true,
            "has_rsvp": false,
            "has_calendar_invites": false,
            "rsvp_limit": null,
            "is_recurring": false,
            "recurrence_rule": null,
            "recurrence_text": null,
            "date_start": "2026-08-03T20:53:42+00:00",
            "date_end": "2026-08-03T22:53:42+00:00",
            "timezone": null,
            "busy_type": null,
            "reminder_before": null,
            "date_range_formatted": "Mon, Aug 3, 2026 (all day)",
            "public_url": "http://addcal.co/e/ap3xucsxrxyj",
            "embed_url": "http://addcal.co/e/ap3xucsxrxyj",
            "location_url": null,
            "image_url": null,
            "timezone_readable": null,
            "calendar": {
                "uid": "ndi7c217vncr",
                "public_id": "cal_ndi7c217vncr",
                "short_link": null,
                "name": "eveniet debitis voluptates",
                "internal_name": "voluptates nostrum ex",
                "description": "",
                "timezone": "Africa/Porto-Novo",
                "week_begins": 0,
                "public_url": "http://addcal.co/c/ndi7c217vncr",
                "created_at": "2026-08-28T03:20:12.000000Z",
                "updated_at": "2026-08-28T03:20:12.000000Z"
            },
            "created_at": "2026-08-28T03:20:12.000000Z",
            "updated_at": "2026-08-28T03:20:12.000000Z"
        }
    ]
}
```

### Get Event by UID

`GET /api/events/{event_public_id}`

**Path parameters**

- `event_public_id` (string, required): The ID of the event public.

**Query parameters**

- `with_html` (boolean, optional): Include HTML variants for calendar links in the response

**Example request**

```bash
curl --request GET \
  --url 'https://addcal.co/api/events/{event_public_id}' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

**Response 200**

```json
{
    "data": {
        "uid": "w7kge7r8h8q5",
        "public_id": "evt_w7kge7r8h8q5",
        "calendar_uid": "cal_z1apbwfu7ttp",
        "short_link": null,
        "title": "Et similique rem non.",
        "internal_name": null,
        "is_draft": false,
        "description": "<p>Natus aut ex aut laborum quas veniam illum. Itaque eaque nulla rem et doloremque occaecati quas consectetur. Cupiditate dolor vero magnam modi numquam enim explicabo harum.</p>\n\n<p>Blanditiis numquam iste consectetur labore iste. Optio laboriosam alias alias voluptatem ut. Debitis enim a neque quo. Est sunt laborum nihil dicta voluptatem rerum adipisci.</p>",
        "location": "6785 Considine Plaza\nHaleyland, CO 55689-9043",
        "is_all_day": false,
        "has_rsvp": false,
        "has_calendar_invites": false,
        "rsvp_limit": null,
        "is_recurring": false,
        "recurrence_rule": null,
        "recurrence_text": null,
        "date_start": "2026-08-21T14:11:30-05:00",
        "date_end": "2026-08-21T16:11:30-05:00",
        "timezone": "America/Eirunepe",
        "busy_type": null,
        "reminder_before": null,
        "date_range_formatted": "Fri, Aug 21, 2026 2:11 PM - 4:11 PM",
        "public_url": "http://addcal.co/e/w7kge7r8h8q5",
        "embed_url": "http://addcal.co/e/w7kge7r8h8q5",
        "location_url": null,
        "image_url": null,
        "timezone_readable": "-05 / GMT-05:00",
        "calendar": {
            "uid": "z1apbwfu7ttp",
            "public_id": "cal_z1apbwfu7ttp",
            "short_link": null,
            "name": "totam nobis voluptates",
            "internal_name": "explicabo est laboriosam",
            "description": "",
            "timezone": "Europe/Moscow",
            "week_begins": 1,
            "public_url": "http://addcal.co/c/z1apbwfu7ttp",
            "created_at": "2026-08-28T03:20:12.000000Z",
            "updated_at": "2026-08-28T03:20:12.000000Z"
        },
        "created_at": "2026-08-28T03:20:12.000000Z",
        "updated_at": "2026-08-28T03:20:12.000000Z"
    },
    "links": {
        "event_page": "http://addcal.co/e/w7kge7r8h8q5",
        "auto": "https://addcal.co/e/w7kge7r8h8q5/auto",
        "google": "https://addcal.co/e/w7kge7r8h8q5/google",
        "apple": "https://addcal.co/e/w7kge7r8h8q5/apple",
        "outlook": "https://addcal.co/e/w7kge7r8h8q5/outlook",
        "outlook_web": "https://addcal.co/e/w7kge7r8h8q5/outlook_web",
        "yahoo": "https://addcal.co/e/w7kge7r8h8q5/yahoo",
        "office365": "https://addcal.co/e/w7kge7r8h8q5/office365",
        "ics": "https://addcal.co/e/w7kge7r8h8q5/ics"
    },
    "html": {
        "single-button": "Add to Calendar Button",
        "icon-buttons-single-row": "Buttons With Icons",
        "icons": "Text with Icons",
        "dot-sep": "Text (dot separated)",
        "space-sep": "Text (space separated)"
    }
}
```

### Index Calendar Events

`GET /api/calendars/{calendar_public_id}/events`

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.

**Query parameters**

- `range` (string, optional): Filter events by time range. Options: 'all', 'upcoming', 'past'
- `search` (string, optional): Search events by title or internal name
- `calendar` (string, optional): Filter events by calendar ID
- `start_date` (string, optional): Filter events starting from this date (ISO 8601 format)
- `end_date` (string, optional): Filter events ending before this date (ISO 8601 format)
- `rsvp` (boolean, optional): Only return events with RSVPs enabled (true) or disabled (false)
- `invites` (boolean, optional): Only return events with calendar invites enabled (true) or disabled (false)

**Body parameters** (`application/json`)

- `range` (string, optional): No description. Options: `all`, `upcoming`, `past`.
- `search` (string, optional): Must not be greater than 255 characters.
- `calendar` (string, optional): Must not be greater than 255 characters.
- `start_date` (string, optional): Must be a valid date.
- `end_date` (string, optional): Must be a valid date.
- `rsvp` (string, optional): No description. Options: `1`, `0`, `true`, `false`.
- `invites` (string, optional): No description. Options: `1`, `0`, `true`, `false`.

**Example request**

```bash
curl --request GET \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/events' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

**Response 200**

```json
{
    "data": [
        {
            "uid": "izypfqsyeoxh",
            "public_id": "evt_izypfqsyeoxh",
            "calendar_uid": "cal_49o2h4qqhaux",
            "short_link": null,
            "title": "Accusamus illum non maxime aspernatur.",
            "internal_name": null,
            "is_draft": false,
            "description": "<p>Quae qui qui blanditiis quisquam aut eum. Et ullam at a. Omnis soluta dolorem optio alias qui.</p>\n\n<p>Doloribus quia dolore consequatur. Rem est provident occaecati et consequatur recusandae ut. Explicabo repudiandae beatae explicabo. Praesentium architecto quod velit aut architecto.</p>",
            "location": "78358 Koch Brooks\nNorth Neoma, WA 03464",
            "is_all_day": true,
            "has_rsvp": false,
            "has_calendar_invites": false,
            "rsvp_limit": null,
            "is_recurring": false,
            "recurrence_rule": null,
            "recurrence_text": null,
            "date_start": "2026-08-23T09:22:57+00:00",
            "date_end": "2026-08-23T12:22:57+00:00",
            "timezone": null,
            "busy_type": null,
            "reminder_before": null,
            "date_range_formatted": "Sun, Aug 23, 2026 (all day)",
            "public_url": "http://addcal.co/e/izypfqsyeoxh",
            "embed_url": "http://addcal.co/e/izypfqsyeoxh",
            "location_url": null,
            "image_url": null,
            "timezone_readable": null,
            "calendar": {
                "uid": "49o2h4qqhaux",
                "public_id": "cal_49o2h4qqhaux",
                "short_link": null,
                "name": "culpa sint fugit",
                "internal_name": "commodi delectus dolorem",
                "description": "",
                "timezone": "America/Santo_Domingo",
                "week_begins": 1,
                "public_url": "http://addcal.co/c/49o2h4qqhaux",
                "created_at": "2026-08-28T03:20:12.000000Z",
                "updated_at": "2026-08-28T03:20:12.000000Z"
            },
            "created_at": "2026-08-28T03:20:12.000000Z",
            "updated_at": "2026-08-28T03:20:12.000000Z"
        },
        {
            "uid": "qtre0reodap9",
            "public_id": "evt_qtre0reodap9",
            "calendar_uid": "cal_zlbtxo9tw4e7",
            "short_link": null,
            "title": "Tenetur adipisci est cupiditate excepturi consectetur.",
            "internal_name": null,
            "is_draft": false,
            "description": "<p>Quas cupiditate voluptatem dolores officia. Sunt itaque aut voluptatum ipsum amet ut possimus. Debitis eos tenetur sed doloremque atque eligendi asperiores. Possimus suscipit officiis omnis ab velit tempore a.</p>\n\n<p>Maiores ut quae molestias. Voluptatem nisi adipisci beatae maxime fugit et qui. Nam natus unde magnam nisi perferendis. Repudiandae totam sint sed autem accusantium.</p>",
            "location": null,
            "is_all_day": true,
            "has_rsvp": false,
            "has_calendar_invites": false,
            "rsvp_limit": null,
            "is_recurring": false,
            "recurrence_rule": null,
            "recurrence_text": null,
            "date_start": "2026-09-15T06:22:07+00:00",
            "date_end": "2026-09-15T08:22:07+00:00",
            "timezone": null,
            "busy_type": null,
            "reminder_before": null,
            "date_range_formatted": "Tue, Sep 15, 2026 (all day)",
            "public_url": "http://addcal.co/e/qtre0reodap9",
            "embed_url": "http://addcal.co/e/qtre0reodap9",
            "location_url": null,
            "image_url": null,
            "timezone_readable": null,
            "calendar": {
                "uid": "zlbtxo9tw4e7",
                "public_id": "cal_zlbtxo9tw4e7",
                "short_link": null,
                "name": "recusandae aut cum",
                "internal_name": null,
                "description": "<p>Odit sit quo pariatur sunt ut dolores et. Dolor repellat alias nemo. Beatae quia rerum esse veniam sed. Enim ut autem ut doloremque sed.</p>",
                "timezone": "Atlantic/Reykjavik",
                "week_begins": 5,
                "public_url": "http://addcal.co/c/zlbtxo9tw4e7",
                "created_at": "2026-08-28T03:20:12.000000Z",
                "updated_at": "2026-08-28T03:20:12.000000Z"
            },
            "created_at": "2026-08-28T03:20:12.000000Z",
            "updated_at": "2026-08-28T03:20:12.000000Z"
        }
    ]
}
```

### Create Event

`POST /api/calendars/{calendar_public_id}/events`

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.

**Query parameters**

- `with_html` (boolean, optional): Include HTML variants for calendar links in the response

**Body parameters** (`application/json`)

- `title` (string, required): Must not be greater than 255 characters.
- `internal_name` (string, optional): Must not be greater than 255 characters.
- `is_draft` (boolean, optional): No description.
- `description` (string, optional): No description.
- `location` (string, optional): Must not be greater than 255 characters.
- `is_all_day` (boolean, optional): No description.
- `recurrence_rule` (string, optional): No description.
- `series_title` (string, optional): Must not be greater than 255 characters.
- `has_rsvp` (boolean, optional): No description.
- `date_start` (string, required): Must be a valid date.
- `date_end` (string, required): Must be a valid date. Must be a date after or equal to date_start.
- `timezone` (string, required): Must be a valid time zone, such as Africa/Accra.
- `busy_type` (string, optional): No description. Options: `busy`, `free`.
- `reminder_before` (integer, optional): Must be at least 0.
- `short_link` (string, optional): Must match the regex /^[a-zA-Z0-9-]+$/. Must not be greater than 50 characters.

**Example request**

```bash
curl --request POST \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/events' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
    "title": "qfklgofxpwqrzoyyso",
    "internal_name": "qnejarzznkmdbpdzsvgawqge",
    "is_draft": true,
    "description": "Sed quia assumenda hic sed.",
    "location": "yhvzbvbwzdunsfdynvfngckud",
    "is_all_day": false,
    "series_title": "gymxabwgycqcqerkqam",
    "has_rsvp": true,
    "date_start": "2026-08-28T03:20:12",
    "date_end": "2038-06-19",
    "timezone": "Asia/Kuala_Lumpur",
    "busy_type": "free",
    "reminder_before": 38,
    "short_link": "bdqcwkcthudpkbrdnnzhbhspl"
}'
```

**Response 200**

```json
{
    "data": {
        "uid": "7v4ykqe3kiwl",
        "public_id": "evt_7v4ykqe3kiwl",
        "calendar_uid": "cal_fo3p4eu2bv2c",
        "short_link": null,
        "title": "Et rerum sint sit tempora sapiente veritatis.",
        "internal_name": null,
        "is_draft": false,
        "description": "<p>Eum officia harum quaerat voluptate laborum omnis deleniti. Culpa qui et nobis quae non ut. Pariatur esse deleniti doloribus non eos beatae dolor laudantium.</p>\n\n<p>Corrupti et fuga nihil. Vel itaque et et. Quia dolorem repudiandae saepe eveniet. Et enim et voluptatum quis expedita aspernatur adipisci.</p>",
        "location": null,
        "is_all_day": false,
        "has_rsvp": false,
        "has_calendar_invites": false,
        "rsvp_limit": null,
        "is_recurring": false,
        "recurrence_rule": null,
        "recurrence_text": null,
        "date_start": "2026-07-31T11:48:47+08:00",
        "date_end": "2026-07-31T12:48:47+08:00",
        "timezone": "Asia/Shanghai",
        "busy_type": null,
        "reminder_before": null,
        "date_range_formatted": "Fri, Jul 31, 2026 11:48 AM - 12:48 PM",
        "public_url": "http://addcal.co/e/7v4ykqe3kiwl",
        "embed_url": "http://addcal.co/e/7v4ykqe3kiwl",
        "location_url": null,
        "image_url": null,
        "timezone_readable": "CST / GMT+08:00",
        "calendar": {
            "uid": "fo3p4eu2bv2c",
            "public_id": "cal_fo3p4eu2bv2c",
            "short_link": null,
            "name": "et dolor commodi",
            "internal_name": null,
            "description": "<p>Quos corporis minima non impedit et. Architecto et velit natus. Sed id necessitatibus omnis atque ipsa rerum. Unde quo labore eos sed.</p>",
            "timezone": "America/St_Lucia",
            "week_begins": 1,
            "public_url": "http://addcal.co/c/fo3p4eu2bv2c",
            "created_at": "2026-08-28T03:20:12.000000Z",
            "updated_at": "2026-08-28T03:20:12.000000Z"
        },
        "created_at": "2026-08-28T03:20:12.000000Z",
        "updated_at": "2026-08-28T03:20:12.000000Z"
    },
    "links": {
        "event_page": "http://addcal.co/e/7v4ykqe3kiwl",
        "auto": "https://addcal.co/e/7v4ykqe3kiwl/auto",
        "google": "https://addcal.co/e/7v4ykqe3kiwl/google",
        "apple": "https://addcal.co/e/7v4ykqe3kiwl/apple",
        "outlook": "https://addcal.co/e/7v4ykqe3kiwl/outlook",
        "outlook_web": "https://addcal.co/e/7v4ykqe3kiwl/outlook_web",
        "yahoo": "https://addcal.co/e/7v4ykqe3kiwl/yahoo",
        "office365": "https://addcal.co/e/7v4ykqe3kiwl/office365",
        "ics": "https://addcal.co/e/7v4ykqe3kiwl/ics"
    },
    "html": {
        "single-button": "Add to Calendar Button",
        "icon-buttons-single-row": "Buttons With Icons",
        "icons": "Text with Icons",
        "dot-sep": "Text (dot separated)",
        "space-sep": "Text (space separated)"
    }
}
```

**Response 409** — When the team's event limit has been exceeded

```json
{
    "message": "You have reached your monthly event limit of 10. Please upgrade your plan to create more events.",
    "current": 10,
    "limit": 10,
    "remaining": 0,
    "would_exceed_by": 1,
    "is_unlimited": false,
    "limit_type": "monthly"
}
```

### Get Event

`GET /api/calendars/{calendar_public_id}/events/{public_id}`

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.
- `public_id` (string, required): The ID of the public.

**Query parameters**

- `with_html` (boolean, optional): Include HTML variants for calendar links in the response

**Example request**

```bash
curl --request GET \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/events/{public_id}' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

**Response 200**

```json
{
    "data": {
        "uid": "yead8xfb2wf7",
        "public_id": "evt_yead8xfb2wf7",
        "calendar_uid": "cal_jox7j7hp6lhs",
        "short_link": null,
        "title": "Sunt quis error et maxime ea.",
        "internal_name": null,
        "is_draft": false,
        "description": "<p>Sint natus nam repudiandae recusandae aut a sit. Quis eos vero amet veniam iusto. Sunt ut reprehenderit rerum commodi. Voluptatem voluptatem voluptatibus laboriosam voluptates.</p>\n\n<p>Et eos ut consequatur deleniti voluptates rem nam. Assumenda tempora est sunt et est facere. Et illum unde et natus.</p>",
        "location": "405 Graham Drives\nLake Chelsea, AR 03463",
        "is_all_day": false,
        "has_rsvp": false,
        "has_calendar_invites": false,
        "rsvp_limit": null,
        "is_recurring": false,
        "recurrence_rule": null,
        "recurrence_text": null,
        "date_start": "2026-09-04T22:45:56-05:00",
        "date_end": "2026-09-05T00:45:56-05:00",
        "timezone": "America/North_Dakota/Beulah",
        "busy_type": null,
        "reminder_before": null,
        "date_range_formatted": "Fri, Sep 4, 2026 10:45 PM - Sat, Sep 5, 2026 12:45 AM",
        "public_url": "http://addcal.co/e/yead8xfb2wf7",
        "embed_url": "http://addcal.co/e/yead8xfb2wf7",
        "location_url": null,
        "image_url": null,
        "timezone_readable": "CDT / GMT-05:00",
        "calendar": {
            "uid": "jox7j7hp6lhs",
            "public_id": "cal_jox7j7hp6lhs",
            "short_link": null,
            "name": "blanditiis a aspernatur",
            "internal_name": null,
            "description": "",
            "timezone": "Africa/Bamako",
            "week_begins": 0,
            "public_url": "http://addcal.co/c/jox7j7hp6lhs",
            "created_at": "2026-08-28T03:20:12.000000Z",
            "updated_at": "2026-08-28T03:20:12.000000Z"
        },
        "created_at": "2026-08-28T03:20:12.000000Z",
        "updated_at": "2026-08-28T03:20:12.000000Z"
    },
    "links": {
        "event_page": "http://addcal.co/e/yead8xfb2wf7",
        "auto": "https://addcal.co/e/yead8xfb2wf7/auto",
        "google": "https://addcal.co/e/yead8xfb2wf7/google",
        "apple": "https://addcal.co/e/yead8xfb2wf7/apple",
        "outlook": "https://addcal.co/e/yead8xfb2wf7/outlook",
        "outlook_web": "https://addcal.co/e/yead8xfb2wf7/outlook_web",
        "yahoo": "https://addcal.co/e/yead8xfb2wf7/yahoo",
        "office365": "https://addcal.co/e/yead8xfb2wf7/office365",
        "ics": "https://addcal.co/e/yead8xfb2wf7/ics"
    },
    "html": {
        "single-button": "Add to Calendar Button",
        "icon-buttons-single-row": "Buttons With Icons",
        "icons": "Text with Icons",
        "dot-sep": "Text (dot separated)",
        "space-sep": "Text (space separated)"
    }
}
```

### Update Event

`PUT /api/calendars/{calendar_public_id}/events/{public_id}`

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.
- `public_id` (string, required): The ID of the public.

**Query parameters**

- `with_html` (boolean, optional): Include HTML variants for calendar links in the response

**Body parameters** (`application/json`)

- `title` (string, required): Must not be greater than 255 characters.
- `internal_name` (string, optional): Must not be greater than 255 characters.
- `is_draft` (boolean, optional): No description.
- `description` (string, optional): No description.
- `location` (string, optional): Must not be greater than 255 characters.
- `is_all_day` (boolean, optional): No description.
- `recurrence_rule` (string, optional): No description.
- `series_title` (string, optional): Must not be greater than 255 characters.
- `has_rsvp` (boolean, optional): No description.
- `send_invite_updates` (boolean, optional): No description.
- `date_start` (string, required): Must be a valid date.
- `date_end` (string, required): Must be a valid date. Must be a date after or equal to date_start.
- `timezone` (string, required): Must be a valid time zone, such as Africa/Accra.
- `busy_type` (string, optional): No description. Options: `busy`, `free`.
- `reminder_before` (integer, optional): Must be at least 0.
- `short_link` (string, optional): Must match the regex /^[a-zA-Z0-9-]+$/. Must not be greater than 50 characters.

**Example request**

```bash
curl --request PUT \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/events/{public_id}' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
    "title": "wzutpboymqcdhnci",
    "internal_name": "d",
    "is_draft": true,
    "description": "Error ut sit omnis amet voluptatem dolore ducimus ratione.",
    "location": "f",
    "is_all_day": true,
    "series_title": "poqrszloaveloubrikvh",
    "has_rsvp": false,
    "send_invite_updates": false,
    "date_start": "2026-08-28T03:20:12",
    "date_end": "2039-03-23",
    "timezone": "Asia/Bangkok",
    "busy_type": "busy",
    "reminder_before": 79,
    "short_link": "wmtcyxfbohadhiu"
}'
```

**Response 200**

```json
{
    "data": {
        "uid": "zxtmtrgpl1kv",
        "public_id": "evt_zxtmtrgpl1kv",
        "calendar_uid": "cal_hf1t8frn77k5",
        "short_link": null,
        "title": "Recusandae fuga similique natus earum.",
        "internal_name": null,
        "is_draft": false,
        "description": "<p>Non qui veniam eum omnis. Distinctio facilis et molestiae exercitationem minus eligendi tempore. Voluptas minus doloribus saepe provident facilis.</p>\n\n<p>Ad dolor ut et ullam reprehenderit et. Non eum iusto qui ipsa dolorem est. Cum et qui eligendi officia dolores.</p>",
        "location": null,
        "is_all_day": true,
        "has_rsvp": false,
        "has_calendar_invites": false,
        "rsvp_limit": null,
        "is_recurring": false,
        "recurrence_rule": null,
        "recurrence_text": null,
        "date_start": "2026-09-02T02:42:09+00:00",
        "date_end": "2026-09-02T06:42:09+00:00",
        "timezone": null,
        "busy_type": null,
        "reminder_before": null,
        "date_range_formatted": "Wed, Sep 2, 2026 (all day)",
        "public_url": "http://addcal.co/e/zxtmtrgpl1kv",
        "embed_url": "http://addcal.co/e/zxtmtrgpl1kv",
        "location_url": null,
        "image_url": null,
        "timezone_readable": null,
        "calendar": {
            "uid": "hf1t8frn77k5",
            "public_id": "cal_hf1t8frn77k5",
            "short_link": null,
            "name": "voluptatem sed neque",
            "internal_name": "molestias animi distinctio",
            "description": "<p>Non unde consectetur est velit. Recusandae tempore et tempora similique. Voluptate et totam voluptas voluptates.</p>",
            "timezone": "Africa/Libreville",
            "week_begins": 6,
            "public_url": "http://addcal.co/c/hf1t8frn77k5",
            "created_at": "2026-08-28T03:20:12.000000Z",
            "updated_at": "2026-08-28T03:20:12.000000Z"
        },
        "created_at": "2026-08-28T03:20:12.000000Z",
        "updated_at": "2026-08-28T03:20:12.000000Z"
    },
    "links": {
        "event_page": "http://addcal.co/e/zxtmtrgpl1kv",
        "auto": "https://addcal.co/e/zxtmtrgpl1kv/auto",
        "google": "https://addcal.co/e/zxtmtrgpl1kv/google",
        "apple": "https://addcal.co/e/zxtmtrgpl1kv/apple",
        "outlook": "https://addcal.co/e/zxtmtrgpl1kv/outlook",
        "outlook_web": "https://addcal.co/e/zxtmtrgpl1kv/outlook_web",
        "yahoo": "https://addcal.co/e/zxtmtrgpl1kv/yahoo",
        "office365": "https://addcal.co/e/zxtmtrgpl1kv/office365",
        "ics": "https://addcal.co/e/zxtmtrgpl1kv/ics"
    },
    "html": {
        "single-button": "Add to Calendar Button",
        "icon-buttons-single-row": "Buttons With Icons",
        "icons": "Text with Icons",
        "dot-sep": "Text (dot separated)",
        "space-sep": "Text (space separated)"
    }
}
```

### Delete Event

`DELETE /api/calendars/{calendar_public_id}/events/{public_id}`

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.
- `public_id` (string, required): The ID of the public.

**Body parameters** (`application/json`)

- `notify_invitees` (boolean, optional): When true and the event has calendar invites, email a cancellation to every invited attendee so the event is removed from their calendars. Defaults to false.

**Example request**

```bash
curl --request DELETE \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/events/{public_id}' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

### Generate Signed URL for Event

`POST /api/calendars/{calendar_public_id}/events/{event_public_id}/signed-url`

Generate a cryptographically signed URL for a protected event. The signed URL grants temporary access and expires after the specified number of days.

The event must have an access code set. If no `expiry_days` is provided, the default is 30 days.

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.
- `event_public_id` (string, required): The ID of the event public.

**Body parameters** (`application/json`)

- `expiry_days` (integer, optional): Number of days until the signed URL expires. Min 1, max 365.

**Example request**

```bash
curl --request POST \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/events/{event_public_id}/signed-url' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
    "expiry_days": 30
}'
```

**Response 200**

```json
{
    "url": "https://addcal.co/e/evt_abc123?expires=1741000000&signature=abc..."
}
```

**Response 422**

```json
{
    "error": "Event does not have an access code set."
}
```

## Events > RSVPs

APIs for managing event RSVP responses.

## Working with Custom Form Fields

Events can have custom forms with additional fields beyond the standard `name` and `email`. To create an RSVP with custom field data:

1. First, fetch the event details using the **Get Event** endpoint (`GET /api/calendars/{calendar}/events/{event}`)
2. Check the `custom_form` object in the response - it contains a `fields` array with all form fields
3. Use each field's `slug` property as the key when submitting custom field data

### Example Workflow

```
GET /api/calendars/cal_abc123/events/evt_xyz789

Response:
{
  "data": {
    "custom_form": {
      "fields": [
        { "slug": "company", "label": "Company Name", "field_type": "text", "is_required": false },
        { "slug": "dietary_requirements", "label": "Dietary Requirements", "field_type": "dropdown", "is_required": true,
          "options": [{ "label": "Vegetarian", "value": "vegetarian" }, { "label": "None", "value": "none" }] }
      ]
    }
  }
}
```

Then create the RSVP, passing the custom field values in `custom_fields`, keyed by slug:

```
POST /api/calendars/cal_abc123/events/evt_xyz789/rsvps

{
  "name": "John Doe",
  "email": "john@example.com",
  "response_type": "yes",
  "custom_fields": {
    "company": "Acme Inc",
    "dietary_requirements": "vegetarian"
  }
}
```

For fields of type `name_field` and `email_field`, send the value as the top-level `name` / `email`
instead of inside `custom_fields`.

### Strict validation (opt-in)

By default the API is lenient: `custom_fields` are stored as sent, without enforcing the form's
required fields, option lists, or field types. This keeps existing integrations working.

Pass `"strict": true` to validate the submission exactly like the public RSVP form: fields marked
`is_required` must be present, `dropdown`/`radio` values must be one of the field's `options[].value`,
and typed fields (e.g. `marketing_consent`) must match their type. Note `marketing_consent` values
must be a JSON boolean (`true`/`false`), not a string like `"True"`.

Earlier versions of this API accepted these values as a flat `data` object. That shape is still
accepted, but it is deprecated: prefer `custom_fields`.

### List RSVPs

`GET /api/calendars/{calendar_public_id}/events/{event_public_id}/rsvps`

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.
- `event_public_id` (string, required): The ID of the event public.

**Query parameters**

- `response_type` (string, optional): Filter by response type. Options: 'yes', 'maybe', 'no'
- `search` (string, optional): Search RSVPs by name or email
- `per_page` (integer, optional): Number of results per page (1-100)

**Body parameters** (`application/json`)

- `response_type` (string, optional): No description. Options: `yes`, `maybe`, `no`.
- `search` (string, optional): Must not be greater than 255 characters.
- `per_page` (integer, optional): Must be at least 1. Must not be greater than 100.

**Example request**

```bash
curl --request GET \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/events/{event_public_id}/rsvps' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

**Response 200**

```json
{
    "data": [
        {
            "uid": "28e5b3fb-de64-470d-9189-b76e187dd3d1",
            "public_id": "rsvp_28e5b3fb-de64-470d-9189-b76e187dd3d1",
            "event_uid": "yp9y906q64sy",
            "response_type": "maybe",
            "name": "Robbie Bruen PhD",
            "email": "agerlach@hotmail.com",
            "data": {
                "guests": 2,
                "comment": "Suscipit consequatur laudantium tempora nisi aut nihil aspernatur."
            },
            "formatted_created_at": "2026-08-28 03:20:12",
            "created_at": "2026-08-28T03:20:12.000000Z",
            "updated_at": "2026-08-28T03:20:12.000000Z",
            "event": {
                "uid": "yp9y906q64sy",
                "public_id": "evt_yp9y906q64sy",
                "calendar_uid": "cal_4mwxgiecjmax",
                "short_link": null,
                "title": "Rerum consectetur et rerum.",
                "internal_name": null,
                "is_draft": false,
                "description": "<p>Numquam ipsum sed dolorem velit consequatur velit. Officiis error odit iusto totam laboriosam sed. Quis repellendus amet deserunt et est voluptas suscipit. Molestiae molestiae animi quo quia consectetur explicabo nihil eum.</p>\n\n<p>Alias voluptatem facere ad commodi suscipit. Animi qui asperiores quod velit. Beatae asperiores culpa enim aut magni sint et.</p>",
                "location": "403 Felipe Ports\nSouth Meggiefurt, SC 13640",
                "is_all_day": false,
                "has_rsvp": false,
                "has_calendar_invites": false,
                "rsvp_limit": null,
                "is_recurring": false,
                "recurrence_rule": null,
                "recurrence_text": null,
                "date_start": "2026-09-04T07:06:18+02:00",
                "date_end": "2026-09-04T11:06:18+02:00",
                "timezone": "Europe/Prague",
                "busy_type": null,
                "reminder_before": null,
                "date_range_formatted": "Fri, Sep 4, 2026 7:06 AM - 11:06 AM",
                "public_url": "http://addcal.co/e/yp9y906q64sy",
                "embed_url": "http://addcal.co/e/yp9y906q64sy",
                "location_url": null,
                "image_url": null,
                "timezone_readable": "CEST / GMT+02:00",
                "calendar": {
                    "uid": "4mwxgiecjmax",
                    "public_id": "cal_4mwxgiecjmax",
                    "short_link": null,
                    "name": "ut omnis numquam",
                    "internal_name": "vero autem vitae",
                    "description": "<p>Velit minima aliquid sed explicabo quibusdam ullam a. Facere unde sint doloribus quo rerum. Est repellat in ipsum dolores qui ut.</p>",
                    "timezone": "Europe/Gibraltar",
                    "week_begins": 0,
                    "public_url": "http://addcal.co/c/4mwxgiecjmax",
                    "created_at": "2026-08-28T03:20:12.000000Z",
                    "updated_at": "2026-08-28T03:20:12.000000Z"
                },
                "created_at": "2026-08-28T03:20:12.000000Z",
                "updated_at": "2026-08-28T03:20:12.000000Z"
            }
        },
        {
            "uid": "06f631c9-f451-4037-aebf-31576424356d",
            "public_id": "rsvp_06f631c9-f451-4037-aebf-31576424356d",
            "event_uid": "pakfrdhp5pdm",
            "response_type": "yes",
            "name": "Estel Bayer Sr.",
            "email": "stroman.lenna@crona.com",
            "data": {
                "guests": 3,
                "comment": "Non eos quaerat cupiditate eos ratione ratione odio."
            },
            "formatted_created_at": "2026-08-28 03:20:12",
            "created_at": "2026-08-28T03:20:12.000000Z",
            "updated_at": "2026-08-28T03:20:12.000000Z",
            "event": {
                "uid": "pakfrdhp5pdm",
                "public_id": "evt_pakfrdhp5pdm",
                "calendar_uid": "cal_10u6oafwx5pr",
                "short_link": null,
                "title": "Odio repellendus ut qui perferendis nobis dolorem.",
                "internal_name": null,
                "is_draft": false,
                "description": "<p>Quisquam soluta autem delectus quo quia porro. Fuga totam aut dolor nesciunt deserunt eius velit. Sapiente facilis est omnis ullam. Quidem incidunt amet quia cupiditate itaque nihil.</p>\n\n<p>Quos libero cum ea sed et. Dignissimos repudiandae placeat assumenda ut quae pariatur. Aspernatur officiis vitae voluptatibus harum rerum dolore velit. Laboriosam maiores omnis at neque praesentium et.</p>",
                "location": null,
                "is_all_day": false,
                "has_rsvp": false,
                "has_calendar_invites": false,
                "rsvp_limit": null,
                "is_recurring": false,
                "recurrence_rule": null,
                "recurrence_text": null,
                "date_start": "2026-09-13T22:34:44-04:00",
                "date_end": "2026-09-13T23:34:44-04:00",
                "timezone": "America/Blanc-Sablon",
                "busy_type": null,
                "reminder_before": null,
                "date_range_formatted": "Sun, Sep 13, 2026 10:34 PM - 11:34 PM",
                "public_url": "http://addcal.co/e/pakfrdhp5pdm",
                "embed_url": "http://addcal.co/e/pakfrdhp5pdm",
                "location_url": null,
                "image_url": null,
                "timezone_readable": "AST / GMT-04:00",
                "calendar": {
                    "uid": "10u6oafwx5pr",
                    "public_id": "cal_10u6oafwx5pr",
                    "short_link": null,
                    "name": "cum possimus enim",
                    "internal_name": "vel architecto rerum",
                    "description": "",
                    "timezone": "Atlantic/Azores",
                    "week_begins": 4,
                    "public_url": "http://addcal.co/c/10u6oafwx5pr",
                    "created_at": "2026-08-28T03:20:12.000000Z",
                    "updated_at": "2026-08-28T03:20:12.000000Z"
                },
                "created_at": "2026-08-28T03:20:12.000000Z",
                "updated_at": "2026-08-28T03:20:12.000000Z"
            }
        }
    ]
}
```

### Create RSVP

`POST /api/calendars/{calendar_public_id}/events/{event_public_id}/rsvps`

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.
- `event_public_id` (string, required): The ID of the event public.

**Body parameters** (`application/json`)

- `response_type` (string, required): No description. Options: `yes`, `maybe`, `no`.
- `name` (string, required): Must not be greater than 255 characters.
- `email` (string, required): Must not be greater than 255 characters.
- `strict` (boolean, optional): No description.
- `custom_fields` (object, optional): No description.

**Example request**

```bash
curl --request POST \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/events/{event_public_id}/rsvps' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
    "response_type": "magni",
    "name": "frvxe",
    "email": "augusta.halvorson@example.com",
    "strict": true
}'
```

**Response 200**

```json
{
    "uid": "9259d39e-11e5-45fc-a5e9-65474e89a6a4",
    "public_id": "rsvp_9259d39e-11e5-45fc-a5e9-65474e89a6a4",
    "event_uid": "x7hi8wxomm2h",
    "response_type": "maybe",
    "name": "Ms. Beryl Kunze II",
    "email": "carter86@trantow.com",
    "data": {
        "guests": 0,
        "comment": "Eos eos porro ipsa ducimus."
    },
    "formatted_created_at": "2026-08-28 03:20:12",
    "created_at": "2026-08-28T03:20:12.000000Z",
    "updated_at": "2026-08-28T03:20:12.000000Z",
    "event": {
        "uid": "x7hi8wxomm2h",
        "public_id": "evt_x7hi8wxomm2h",
        "calendar_uid": "cal_lmjv9haksz2i",
        "short_link": null,
        "title": "Doloribus doloribus ut voluptatem est similique.",
        "internal_name": null,
        "is_draft": false,
        "description": "<p>Nihil odit qui totam cupiditate et. Provident architecto voluptatum autem et voluptatibus totam. Eligendi quasi et aliquid. Sequi officiis excepturi voluptas labore blanditiis autem quos.</p>\n\n<p>Et assumenda asperiores quidem in distinctio odit. Nostrum sequi illo non. Ad itaque ut ipsum dolorem eos et.</p>",
        "location": "25886 Tyrel Manors\nTrompfort, NE 02773",
        "is_all_day": false,
        "has_rsvp": false,
        "has_calendar_invites": false,
        "rsvp_limit": null,
        "is_recurring": false,
        "recurrence_rule": null,
        "recurrence_text": null,
        "date_start": "2026-08-08T14:51:16+04:00",
        "date_end": "2026-08-08T18:51:16+04:00",
        "timezone": "Asia/Muscat",
        "busy_type": null,
        "reminder_before": null,
        "date_range_formatted": "Sat, Aug 8, 2026 2:51 PM - 6:51 PM",
        "public_url": "http://addcal.co/e/x7hi8wxomm2h",
        "embed_url": "http://addcal.co/e/x7hi8wxomm2h",
        "location_url": null,
        "image_url": null,
        "timezone_readable": "+04 / GMT+04:00",
        "calendar": {
            "uid": "lmjv9haksz2i",
            "public_id": "cal_lmjv9haksz2i",
            "short_link": null,
            "name": "vitae nisi sint",
            "internal_name": "qui praesentium nesciunt",
            "description": "",
            "timezone": "Europe/Athens",
            "week_begins": 6,
            "public_url": "http://addcal.co/c/lmjv9haksz2i",
            "created_at": "2026-08-28T03:20:12.000000Z",
            "updated_at": "2026-08-28T03:20:12.000000Z"
        },
        "created_at": "2026-08-28T03:20:12.000000Z",
        "updated_at": "2026-08-28T03:20:12.000000Z"
    }
}
```

### Get RSVP

`GET /api/calendars/{calendar_public_id}/events/{event_public_id}/rsvps/{public_id}`

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.
- `event_public_id` (string, required): The ID of the event public.
- `public_id` (string, required): The ID of the public.

**Example request**

```bash
curl --request GET \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/events/{event_public_id}/rsvps/{public_id}' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

**Response 200**

```json
{
    "uid": "b47e0c53-2eb2-40a3-8957-21bf567df8ee",
    "public_id": "rsvp_b47e0c53-2eb2-40a3-8957-21bf567df8ee",
    "event_uid": "p3mwubr0q8wt",
    "response_type": "yes",
    "name": "Fleta Wintheiser",
    "email": "emmet.zieme@braun.com",
    "data": {
        "guests": 0,
        "comment": "Dicta eveniet repellendus doloribus."
    },
    "formatted_created_at": "2026-08-28 03:20:12",
    "created_at": "2026-08-28T03:20:12.000000Z",
    "updated_at": "2026-08-28T03:20:12.000000Z",
    "event": {
        "uid": "p3mwubr0q8wt",
        "public_id": "evt_p3mwubr0q8wt",
        "calendar_uid": "cal_fazboupkz9yi",
        "short_link": null,
        "title": "Sed eos aspernatur dignissimos veritatis.",
        "internal_name": null,
        "is_draft": false,
        "description": "<p>Incidunt necessitatibus quia quae nihil et. Dicta adipisci consectetur consequatur dolores ex quo. Vero suscipit perferendis id quia odit culpa.</p>\n\n<p>Libero ea officiis vitae eum autem deserunt sint. Hic cumque at earum sunt. Est recusandae ea non non incidunt.</p>",
        "location": null,
        "is_all_day": true,
        "has_rsvp": false,
        "has_calendar_invites": false,
        "rsvp_limit": null,
        "is_recurring": false,
        "recurrence_rule": null,
        "recurrence_text": null,
        "date_start": "2026-09-23T12:00:28+00:00",
        "date_end": "2026-09-23T15:00:28+00:00",
        "timezone": null,
        "busy_type": null,
        "reminder_before": null,
        "date_range_formatted": "Wed, Sep 23, 2026 (all day)",
        "public_url": "http://addcal.co/e/p3mwubr0q8wt",
        "embed_url": "http://addcal.co/e/p3mwubr0q8wt",
        "location_url": null,
        "image_url": null,
        "timezone_readable": null,
        "calendar": {
            "uid": "fazboupkz9yi",
            "public_id": "cal_fazboupkz9yi",
            "short_link": null,
            "name": "eum et ipsum",
            "internal_name": null,
            "description": "<p>Non voluptates ipsa in qui. Non quibusdam est qui accusantium ut et. Non voluptate ea non non. Minima amet nesciunt et neque.</p>",
            "timezone": "Europe/Copenhagen",
            "week_begins": 2,
            "public_url": "http://addcal.co/c/fazboupkz9yi",
            "created_at": "2026-08-28T03:20:12.000000Z",
            "updated_at": "2026-08-28T03:20:12.000000Z"
        },
        "created_at": "2026-08-28T03:20:12.000000Z",
        "updated_at": "2026-08-28T03:20:12.000000Z"
    }
}
```

### Update RSVP

`PUT /api/calendars/{calendar_public_id}/events/{event_public_id}/rsvps/{public_id}`

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.
- `event_public_id` (string, required): The ID of the event public.
- `public_id` (string, required): The ID of the public.

**Body parameters** (`application/json`)

- `response_type` (string, optional): No description. Options: `yes`, `maybe`, `no`.
- `name` (string, optional): Must not be greater than 255 characters.
- `email` (string, optional): Must not be greater than 255 characters.
- `strict` (boolean, optional): No description.
- `custom_fields` (object, optional): No description.

**Example request**

```bash
curl --request PUT \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/events/{event_public_id}/rsvps/{public_id}' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
    "response_type": "et",
    "name": "nkazafyx",
    "email": "griffin.christiansen@example.net",
    "strict": false
}'
```

**Response 200**

```json
{
    "uid": "64637cd7-513b-4a9c-918c-932a00115331",
    "public_id": "rsvp_64637cd7-513b-4a9c-918c-932a00115331",
    "event_uid": "excd7jxfpsp5",
    "response_type": "yes",
    "name": "Jovan Labadie Jr.",
    "email": "orowe@rogahn.info",
    "data": {
        "guests": 3,
        "comment": "Aut dolorem dolores qui in ut sunt nisi."
    },
    "formatted_created_at": "2026-08-28 03:20:12",
    "created_at": "2026-08-28T03:20:12.000000Z",
    "updated_at": "2026-08-28T03:20:12.000000Z",
    "event": {
        "uid": "excd7jxfpsp5",
        "public_id": "evt_excd7jxfpsp5",
        "calendar_uid": "cal_xom05jal706d",
        "short_link": null,
        "title": "Culpa voluptatem dolores expedita.",
        "internal_name": null,
        "is_draft": false,
        "description": "<p>Itaque impedit pariatur pariatur consequatur sed doloremque. Nihil molestias esse ea ea ut. Tempore id sed ut mollitia et ut.</p>\n\n<p>Tempore sunt et corporis id. Dolorem aut eaque qui. Facilis molestias temporibus possimus ut. Voluptatum consequatur voluptas et nostrum a.</p>",
        "location": "6700 Hodkiewicz Prairie\nDaynamouth, NE 39778",
        "is_all_day": false,
        "has_rsvp": false,
        "has_calendar_invites": false,
        "rsvp_limit": null,
        "is_recurring": false,
        "recurrence_rule": null,
        "recurrence_text": null,
        "date_start": "2026-08-20T21:46:09+02:00",
        "date_end": "2026-08-20T22:46:09+02:00",
        "timezone": "Africa/Ceuta",
        "busy_type": null,
        "reminder_before": null,
        "date_range_formatted": "Thu, Aug 20, 2026 9:46 PM - 10:46 PM",
        "public_url": "http://addcal.co/e/excd7jxfpsp5",
        "embed_url": "http://addcal.co/e/excd7jxfpsp5",
        "location_url": null,
        "image_url": null,
        "timezone_readable": "CEST / GMT+02:00",
        "calendar": {
            "uid": "xom05jal706d",
            "public_id": "cal_xom05jal706d",
            "short_link": null,
            "name": "et et voluptas",
            "internal_name": "expedita voluptatibus cumque",
            "description": "",
            "timezone": "Europe/Sarajevo",
            "week_begins": 0,
            "public_url": "http://addcal.co/c/xom05jal706d",
            "created_at": "2026-08-28T03:20:12.000000Z",
            "updated_at": "2026-08-28T03:20:12.000000Z"
        },
        "created_at": "2026-08-28T03:20:12.000000Z",
        "updated_at": "2026-08-28T03:20:12.000000Z"
    }
}
```

### Delete RSVP

`DELETE /api/calendars/{calendar_public_id}/events/{event_public_id}/rsvps/{public_id}`

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.
- `event_public_id` (string, required): The ID of the event public.
- `public_id` (string, required): The ID of the public.

**Example request**

```bash
curl --request DELETE \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/events/{event_public_id}/rsvps/{public_id}' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

## Events > Invites

Send real calendar invites (iTIP/iMIP) by email straight from your own integration.

An invite emails the attendee a native calendar request with Yes/No/Maybe buttons; accepting writes
the event into their primary calendar and their reply is tracked back on the invite. Calendar invites
must be enabled on the event (`has_calendar_invites`) for a team on the Business plan, otherwise
these endpoints return `403`.

### Resend Invite by Email

`POST /api/calendars/{calendar_public_id}/events/{event_public_id}/invites/resend`

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.
- `event_public_id` (string, required): The ID of the event public.

**Body parameters** (`application/json`)

- `email` (string, required): The attendee email whose invite to resend.
- `source` (string, optional): No description. Options: `api`, `zapier`.

**Example request**

```bash
curl --request POST \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/events/{event_public_id}/invites/resend' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
    "email": "john@example.com",
    "source": "api"
}'
```

**Response 200**

```json
{
    "data": {
        "public_id": "inv_7h0irrhi7u73",
        "event_uid": "xm6fikf4e38d",
        "email": "lockman.sigurd@example.net",
        "status": "pending",
        "source": "event_page",
        "sent_at": null,
        "responded_at": null,
        "cancelled_at": null,
        "created_at": "2026-08-28T03:20:12+00:00",
        "updated_at": "2026-08-28T03:20:12+00:00"
    }
}
```

**Response 404** — Not found

```json
{
    "message": "No invite found for that email address."
}
```

### Cancel Invite by Email

`POST /api/calendars/{calendar_public_id}/events/{event_public_id}/invites/cancel`

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.
- `event_public_id` (string, required): The ID of the event public.

**Body parameters** (`application/json`)

- `email` (string, required): The attendee email whose invite to cancel.
- `source` (string, optional): No description. Options: `api`, `zapier`.

**Example request**

```bash
curl --request POST \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/events/{event_public_id}/invites/cancel' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
    "email": "john@example.com",
    "source": "zapier"
}'
```

**Response 204** — Invite cancelled

**Response 404** — Not found

```json
{
    "message": "No invite found for that email address."
}
```

### Resend Invite

`POST /api/calendars/{calendar_public_id}/events/{event_public_id}/invites/{invite_public_id}/resend`

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.
- `event_public_id` (string, required): The ID of the event public.
- `invite_public_id` (string, required): The ID of the invite public.

**Example request**

```bash
curl --request POST \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/events/{event_public_id}/invites/{invite_public_id}/resend' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

**Response 200**

```json
{
    "data": {
        "public_id": "inv_5spu9i0901pe",
        "event_uid": "mllwqvcedxfn",
        "email": "brenden01@example.com",
        "status": "pending",
        "source": "event_page",
        "sent_at": null,
        "responded_at": null,
        "cancelled_at": null,
        "created_at": "2026-08-28T03:20:12+00:00",
        "updated_at": "2026-08-28T03:20:12+00:00"
    }
}
```

**Response 422** — Cannot resend

```json
{
    "message": "Cancelled invites cannot be resent."
}
```

### Send Invite

`POST /api/calendars/{calendar_public_id}/events/{event_public_id}/invites`

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.
- `event_public_id` (string, required): The ID of the event public.

**Body parameters** (`application/json`)

- `email` (string, required): The attendee email to invite.
- `source` (string, optional): No description. Options: `api`, `zapier`.

**Example request**

```bash
curl --request POST \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/events/{event_public_id}/invites' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
    "email": "john@example.com",
    "source": "api"
}'
```

**Response 200**

```json
{
    "data": {
        "public_id": "inv_ltilx76zq5x5",
        "event_uid": "cr2ws2a44oze",
        "email": "trantow.christopher@example.org",
        "status": "pending",
        "source": "event_page",
        "sent_at": null,
        "responded_at": null,
        "cancelled_at": null,
        "created_at": "2026-08-28T03:20:12+00:00",
        "updated_at": "2026-08-28T03:20:12+00:00"
    }
}
```

**Response 403** — Invites not enabled

```json
{
    "message": "Calendar invites are not enabled for this event."
}
```

**Response 422** — Event has ended

```json
{
    "message": "Sorry, this event has already ended."
}
```

### List Invites

`GET /api/calendars/{calendar_public_id}/events/{event_public_id}/invites`

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.
- `event_public_id` (string, required): The ID of the event public.

**Query parameters**

- `status` (string, optional): Filter by invite status (e.g. 'sent', 'accepted', 'declined')
- `search` (string, optional): Search invites by email
- `per_page` (integer, optional): Number of results per page (1-100)

**Body parameters** (`application/json`)

- `status` (string, optional): No description. Options: `pending`, `sent`, `accepted`, `tentative`, `declined`, `bounced`, `failed`, `cancelled`.
- `search` (string, optional): Must not be greater than 255 characters.
- `per_page` (integer, optional): Must be at least 1. Must not be greater than 100.

**Example request**

```bash
curl --request GET \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/events/{event_public_id}/invites' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

**Response 200**

```json
{
    "data": [
        {
            "public_id": "inv_bcusq2kzoiah",
            "event_uid": "h9zr80tdw7lw",
            "email": "keanu80@example.net",
            "status": "pending",
            "source": "event_page",
            "sent_at": null,
            "responded_at": null,
            "cancelled_at": null,
            "created_at": "2026-08-28T03:20:12+00:00",
            "updated_at": "2026-08-28T03:20:12+00:00"
        },
        {
            "public_id": "inv_ketaqoreawrc",
            "event_uid": "z1jwacosbo8s",
            "email": "tmarvin@example.org",
            "status": "pending",
            "source": "event_page",
            "sent_at": null,
            "responded_at": null,
            "cancelled_at": null,
            "created_at": "2026-08-28T03:20:12+00:00",
            "updated_at": "2026-08-28T03:20:12+00:00"
        }
    ]
}
```

### Get Invite

`GET /api/calendars/{calendar_public_id}/events/{event_public_id}/invites/{public_id}`

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.
- `event_public_id` (string, required): The ID of the event public.
- `public_id` (string, required): The ID of the public.

**Example request**

```bash
curl --request GET \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/events/{event_public_id}/invites/{public_id}' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

**Response 200**

```json
{
    "data": {
        "public_id": "inv_fq81198ikx6u",
        "event_uid": "ozcmxa77y187",
        "email": "kihn.berniece@example.org",
        "status": "pending",
        "source": "event_page",
        "sent_at": null,
        "responded_at": null,
        "cancelled_at": null,
        "created_at": "2026-08-28T03:20:12+00:00",
        "updated_at": "2026-08-28T03:20:12+00:00"
    }
}
```

### Cancel Invite

`DELETE /api/calendars/{calendar_public_id}/events/{event_public_id}/invites/{public_id}`

**Path parameters**

- `calendar_public_id` (string, required): The ID of the calendar public.
- `event_public_id` (string, required): The ID of the event public.
- `public_id` (string, required): The ID of the public.

**Example request**

```bash
curl --request DELETE \
  --url 'https://addcal.co/api/calendars/{calendar_public_id}/events/{event_public_id}/invites/{public_id}' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

**Response 204** — Invite cancelled

**Response 422** — Not active

```json
{
    "message": "This invite is no longer active."
}
```

## Account

APIs for managing the authenticated user's account

### Get Current User

`GET /api/users/me`

**Example request**

```bash
curl --request GET \
  --url 'https://addcal.co/api/users/me' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

**Response 200**

```json
{
    "user": {
        "uid": "ta8ck2mzgfdv",
        "name": "Test User",
        "email": "test@example.com",
        "created_at": "2025-07-27T06:39:24.000000Z",
        "updated_at": "2026-08-28T00:02:40.000000Z"
    },
    "teams": [
        {
            "uid": "v08acy4z0l57",
            "name": "Email Limit Test (1990 used)",
            "personal_team": false,
            "is_owner": true,
            "is_subscribed": true,
            "timezone": null,
            "created_at": "2026-07-19T04:28:25.000000Z",
            "updated_at": "2026-07-19T04:28:25.000000Z"
        },
        {
            "uid": "vvmknusj2w7g",
            "name": "Email Limit Test (990 used)",
            "personal_team": false,
            "is_owner": true,
            "is_subscribed": true,
            "timezone": null,
            "created_at": "2026-07-19T04:28:25.000000Z",
            "updated_at": "2026-07-19T05:31:52.000000Z"
        },
        {
            "uid": "b9jftdrz6ad2",
            "name": "Test User's Team",
            "personal_team": true,
            "is_owner": true,
            "is_subscribed": true,
            "timezone": null,
            "created_at": "2025-07-27T06:39:24.000000Z",
            "updated_at": "2026-07-05T05:17:19.000000Z"
        }
    ],
    "current_team": {
        "uid": "b9jftdrz6ad2",
        "name": "Test User's Team",
        "personal_team": true,
        "is_owner": true,
        "is_subscribed": true,
        "timezone": null,
        "created_at": "2025-07-27T06:39:24.000000Z",
        "updated_at": "2026-07-05T05:17:19.000000Z"
    }
}
```

## Dynamic Links

Generate add-to-calendar redirect URLs from query parameters. Requires a Dynamic Link Key (Business plan). The user is redirected to their chosen calendar service with the event pre-filled.

### /api/dyn

`GET /api/dyn`

**Query parameters**

- `uid` (string, required): Your Dynamic Link Key identifier.
- `service` (string, required): Calendar service to redirect to. Accepted: google, apple, outlook, outlook_web, office365, yahoo, ics, manual.
- `title` (string, required): Event title. Max 255 characters.
- `start` (string, required): Start date/time in ISO 8601 format.
- `end` (string, optional): End date/time in ISO 8601 format. Defaults to 1 hour after start if omitted.
- `duration` (integer, optional): Duration in minutes. Takes precedence over end.
- `timezone` (string, optional): IANA timezone. Required for timed events.
- `all_day_event` (boolean, optional): Set to true for all-day events.
- `description` (string, optional): Event description. Max 2000 characters.
- `location` (string, optional): Physical address or virtual meeting URL. Max 255 characters.
- `alarm` (integer, optional): Reminder in minutes before the event.
- `recurring` (string, optional): RFC 5545 recurrence rule (RRULE).
- `transp` (string, optional): Busy status: OPAQUE (busy) or TRANSPARENT (free). Defaults to OPAQUE.

**Body parameters** (`application/json`)

- `uid` (string, required): No description.
- `title` (string, required): Must not be greater than 255 characters.
- `start` (string, required): Must be a valid date.
- `end` (string, optional): Must be a valid date. Must be a date after or equal to start.
- `duration` (integer, optional): Must be at least 1.
- `all_day_event` (string, optional): No description.
- `timezone` (string, required): Must be a valid time zone, such as Africa/Accra.
- `description` (string, optional): Must not be greater than 2000 characters.
- `location` (string, optional): Must not be greater than 255 characters.
- `alarm` (integer, optional): Must be at least 0.
- `recurring` (string, optional): No description.
- `transp` (string, optional): No description. Options: `TRANSPARENT`, `OPAQUE`.
- `service` (string, optional): No description.

**Example request**

```bash
curl --request GET \
  --url 'https://addcal.co/api/dyn' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

**Response 302** — Redirects the user to the chosen calendar service with the event pre-filled.

**Response 403** — Team is not on the Business plan.

**Response 404**

**Response 422** — When validation fails (e.g. missing required params or unrecognised service).

```json
{
    "message": "The provided Dynamic Link parameters were invalid."
}
```

### /api/dyn_ade

`GET /api/dyn_ade`

**Query parameters**

- `client` (string, required): AddEvent compatibility alias for uid. Your Dynamic Link Key identifier.
- `service` (string, required): Calendar service to redirect to. AddEvent values (outlookcom, stream) are automatically mapped. Accepted: google, apple, outlook, outlook_web, office365, yahoo, ics, manual.
- `title` (string, required): Event title. Max 255 characters.
- `start` (string, required): Start date/time in ISO 8601 format.
- `end` (string, optional): End date/time in ISO 8601 format. Defaults to 1 hour after start if omitted.
- `duration` (integer, optional): Duration in minutes. Takes precedence over end.
- `timezone` (string, optional): IANA timezone. Required for timed events.
- `all_day_event` (boolean, optional): Set to true for all-day events.
- `description` (string, optional): Event description. Max 2000 characters.
- `location` (string, optional): Physical address or virtual meeting URL. Max 255 characters.
- `alarm` (integer, optional): Reminder in minutes before the event.
- `recurring` (string, optional): RFC 5545 recurrence rule (RRULE).
- `transp` (string, optional): Busy status: OPAQUE (busy) or TRANSPARENT (free). Defaults to OPAQUE.

**Body parameters** (`application/json`)

- `uid` (string, required): No description.
- `title` (string, required): Must not be greater than 255 characters.
- `start` (string, required): Must be a valid date.
- `end` (string, optional): Must be a valid date. Must be a date after or equal to start.
- `duration` (integer, optional): Must be at least 1.
- `all_day_event` (string, optional): No description.
- `timezone` (string, required): Must be a valid time zone, such as Africa/Accra.
- `description` (string, optional): Must not be greater than 2000 characters.
- `location` (string, optional): Must not be greater than 255 characters.
- `alarm` (integer, optional): Must be at least 0.
- `recurring` (string, optional): No description.
- `transp` (string, optional): No description. Options: `TRANSPARENT`, `OPAQUE`.
- `service` (string, optional): No description.

**Example request**

```bash
curl --request GET \
  --url 'https://addcal.co/api/dyn_ade' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

**Response 302** — Redirects the user to the chosen calendar service with the event pre-filled.

**Response 403** — Team is not on the Business plan.

**Response 404**

**Response 422** — When validation fails (e.g. missing required params or unrecognised service).

```json
{
    "message": "The provided Dynamic Link parameters were invalid."
}
```

## Endpoints

### /api/extension/token

`DELETE /api/extension/token`

**Example request**

```bash
curl --request DELETE \
  --url 'https://addcal.co/api/extension/token' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json'
```

### /api/events/extract

`POST /api/events/extract`

**Body parameters** (`application/json`)

- `text` (string, required): Must be at least 10 characters. Must not be greater than 8000 characters.
- `timezone` (string, optional): Must be a valid time zone, such as Africa/Accra.

**Example request**

```bash
curl --request POST \
  --url 'https://addcal.co/api/events/extract' \
  --header 'Authorization: Bearer YOUR_API_TOKEN' \
  --header 'Accept: application/json' \
  --header 'Content-Type: application/json' \
  --data '{
    "text": "zlfuuwnfess",
    "timezone": "Africa/Casablanca"
}'
```
