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

# Events

> The event lifecycle (draft > published > cancelled), the optional link to a group or course, and the attendee list via API.

Events are scheduled gatherings inside the community (a livestream, a live class, a webinar, an in-person meetup). Through the public API you list events, read a single event's details, mark or unmark a user's attendance, and, with admin scope, create and manage the full lifecycle.

Think of an event like a party invitation: first you draft the invite without sending it (draft), then you hand it out (publish) and people RSVP (attend); if the party is off, you tell the people who signed up instead of pretending the invite never existed (cancel, not delete).

## The lifecycle

Every event moves through three states. The transition always goes forward (you cannot "unpublish" an event; to take it down, cancel it).

```
Draft ──publish──> Published ──cancel──> Cancelled
                   (visible in           (visible as
                    the community)        cancelled)
```

* **Draft:** created by `POST /community/events`. Invisible to members; use it to set up title, description, date and links before you announce.
* **Published:** after `POST /community/events/{eventId}/publish`. Shows up in public listings and starts accepting attendance.
* **Cancelled:** after `POST /community/events/{eventId}/cancel`. Stays visible (marked as cancelled) so anyone who signed up knows it is off.

<Note>
  `publish` and `cancel` are state transitions, not edits. To change the title, date or description of an existing event, use `PUT /community/events/{eventId}`. To remove the record entirely (instead of cancelling), use `DELETE /community/events/{eventId}`.
</Note>

## Optional link to a group or course

An event can be **standalone** (it appears on the community's general agenda) or **linked** to a group or a course. The link is optional and adds context (a group's event shows up inside that group; a course's event shows up in the course track).

```
Standalone event  ──> community general agenda
Group event       ──> appears in the group (groupId)
Course event      ──> appears in the course (courseId)
```

To find the events of a specific group or course, use the filter endpoints:

```bash theme={null}
# events of a group
curl https://apis.cativalab.digital/tenant/api/v2/community/events/by-group/01HQ0ABCDEF1234567890XYZ \
  -H "Authorization: Bearer cativa_live_..."

# events of a course
curl https://apis.cativalab.digital/tenant/api/v2/community/events/by-course/01HQ0COURSE1234567890XYZ \
  -H "Authorization: Bearer cativa_live_..."
```

## Read endpoints

```bash theme={null}
# list community events
curl https://apis.cativalab.digital/tenant/api/v2/community/events \
  -H "Authorization: Bearer cativa_live_..."

# single event detail
curl https://apis.cativalab.digital/tenant/api/v2/community/events/01HQ5EVENT1234567890XYZ \
  -H "Authorization: Bearer cativa_live_..."

# attendee list for the event
curl https://apis.cativalab.digital/tenant/api/v2/community/events/01HQ5EVENT1234567890XYZ/attendees \
  -H "Authorization: Bearer cativa_live_..."
```

<Note>
  We don't document the field names of each response here (they evolve). Check the **API Reference** tab, under the **Event** tag, for the exact schema of every return.
</Note>

## Create an event (admin scope)

Creating, editing, publishing, cancelling and deleting events requires **admin scope** (organizer). Partner keys with default scope can **read** events and **mark attendance**, but they cannot create or change the lifecycle. Use a key with admin/organizer permission for the write endpoints.

The event starts as a draft. Publish it as a second step, once it's ready to announce.

<Steps>
  <Step title="Create the draft">
    `POST /community/events` with title, dates and (optionally) `groupId` or `courseId`. The response carries the event `id`. It starts invisible to members.
  </Step>

  <Step title="Publish">
    `POST /community/events/{eventId}/publish`. The event starts showing in listings and accepting attendance.
  </Step>

  <Step title="Collect attendance">
    Members call `POST .../attend`. Track who signed up through the `attendees` list.
  </Step>

  <Step title="Cancel if needed">
    `POST /community/events/{eventId}/cancel` keeps the event visible as cancelled for anyone who already signed up. To drop the record entirely, use `DELETE`.
  </Step>
</Steps>

<CodeGroup>
  ```bash cURL theme={null}
  # creates the event as a DRAFT; groupId and courseId are optional (link)
  curl -X POST https://apis.cativalab.digital/tenant/api/v2/community/events \
    -H "Authorization: Bearer cativa_live_..." \
    -H "Content-Type: application/json" \
    -d '{
      "title": "Kickoff livestream",
      "description": "July cohort kickoff.",
      "startsAt": "2026-08-01T19:00:00Z",
      "endsAt": "2026-08-01T20:30:00Z",
      "groupId": "01HQ5GROUP1234567890XYZ"
    }'
  ```

  ```js Node theme={null}
  const res = await fetch('https://apis.cativalab.digital/tenant/api/v2/community/events', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${apiKey}`, // key with admin/organizer scope
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      title: 'Kickoff livestream',
      description: 'July cohort kickoff.',
      startsAt: '2026-08-01T19:00:00Z',
      endsAt: '2026-08-01T20:30:00Z',
      groupId: '01HQ5GROUP1234567890XYZ' // optional; omit for a standalone event
    })
  });
  const event = await res.json();

  // second step: publish when it's ready
  await fetch(`https://apis.cativalab.digital/tenant/api/v2/community/events/${event.id}/publish`, {
    method: 'POST',
    headers: { 'Authorization': `Bearer ${apiKey}` }
  });
  ```
</CodeGroup>

Creation returns the event identifier (use it in the publish, cancel and attend steps). Full schema in the **API Reference** tab, tag **Event**:

```json theme={null}
{
  "id": "01HQ5EVENT1234567890XYZ"
}
```

<Warning>
  Without admin scope, the write endpoints (create, edit, publish, cancel, delete) return `403 forbidden`. That's expected: ask the tenant admin for an organizer key, or leave event creation to the dashboard.
</Warning>

## Mark attendance (attend)

Any user with access to the event marks attendance with `POST .../attend` and removes it with `DELETE .../attend`. Attendance is always for the user tied to the authenticated credential (you don't send `userId` in the body).

```bash theme={null}
# mark attendance
curl -X POST https://apis.cativalab.digital/tenant/api/v2/community/events/01HQ5EVENT1234567890XYZ/attend \
  -H "Authorization: Bearer cativa_live_..."

# unmark attendance
curl -X DELETE https://apis.cativalab.digital/tenant/api/v2/community/events/01HQ5EVENT1234567890XYZ/attend \
  -H "Authorization: Bearer cativa_live_..."
```

The event must be **published** and the user must have **access** to the community (and to the group, if the event is linked to a group that requires a badge). Without access, it returns `403 forbidden`. Once confirmed, attendance shows up in the event's `attendees` list.

## Common errors and questions

<AccordionGroup>
  <Accordion title="I created the event but nobody can see it">
    It's probably still a **draft**. Drafts are invisible to members on purpose. Call `POST /community/events/{eventId}/publish` to take it live. Only after publishing does it show in listings and accept attendance.
  </Accordion>

  <Accordion title="How do I unpublish an event?">
    There is no "unpublish". The transition always moves forward (draft, published, cancelled). To take down an announced event, use `cancel`: it stays visible marked as cancelled so anyone who signed up knows it's off. `DELETE` removes the record entirely (with no notice to attendees).
  </Accordion>

  <Accordion title="403 forbidden when creating or publishing">
    Writes (create, edit, publish, cancel, delete) require **admin scope** (organizer). A default partner key only reads events and marks attendance. Ask the tenant admin for an organizer key, or leave creation to the dashboard.
  </Accordion>

  <Accordion title="403 forbidden marking attendance on an event I can see in the listing">
    Seeing it in the listing isn't the same as having access to the event. If the event is linked to a group that requires a badge, the user needs that badge to attend. Assign the badge (see [Badges as Permissions](/en/concepts/badges-as-permissions)) and retry `attend`.
  </Accordion>

  <Accordion title="I marked attendance twice, is that a problem?">
    No. Marking again is safe: attendance belongs to the credential's user and does not duplicate. `DELETE .../attend` unmarks it; unmarking something that wasn't marked does not error. Treat the attend/unattend pair as idempotent.
  </Accordion>
</AccordionGroup>

## Next steps

<CardGroup cols={2}>
  <Card title="Communities and Spaces" icon="users" href="/en/concepts/communities-and-spaces">
    The Community > Space > Group hierarchy where events can be linked.
  </Card>

  <Card title="Courses and Certificates" icon="graduation-cap" href="/en/concepts/courses-and-certificates">
    How to link an event to a course and its lesson track.
  </Card>

  <Card title="Posts and Comments" icon="message-square" href="/en/concepts/posts-and-comments">
    Post to the group feed to announce and follow up on an event.
  </Card>
</CardGroup>
