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

# Manage event participation

> List events, register and update participants, mark attendance, and finalise or correct it through Floral's public API.

Use event operations to read a workspace's events, keep a participant list in step with another system, and record attendance after the event. The API applies the same rules as the Floral app: capacity, waitlists, registration windows, and attendance finalisation behave identically.

## Prerequisites

* The workspace has the Events add-on, and your token's owner can use Work in that workspace.
* The token has `events:read` to read events and participants, and `events:write` to change them. Each scope grants only its own access; a write token cannot read.
* You can only see events that the token's owner can see in Floral. An event or participant you cannot see returns `404 NOT_FOUND`, exactly as if it did not exist.

If the Events add-on is not available to the workspace, every event operation returns `404 FEATURE_DISABLED`.

Set these values once in your shell before running the examples:

```bash theme={null}
export FLORAL_BASE_URL="https://app.floral.so/api/v1"
export FLORAL_WORKSPACE="your-workspace"
export FLORAL_TOKEN="floral_pat_..."
```

Use a personal access token created for this workspace. The examples use synthetic IDs and values; replace them with values returned by your workspace.

<Warning>
  Keep `FLORAL_TOKEN` in a secret manager outside local development. Never commit it to source control or include it in logs.
</Warning>

## List and filter events

Event collections use opaque cursor pagination with at most 50 items per page. Filter by planning status, attendance finalisation, owner, or a local date range.

```bash theme={null}
curl --get --fail-with-body \
  --url "$FLORAL_BASE_URL/workspaces/$FLORAL_WORKSPACE/events" \
  --header "Authorization: Bearer $FLORAL_TOKEN" \
  --data-urlencode "planningStatus=READY" \
  --data-urlencode "from=2026-09-01" \
  --data-urlencode "to=2026-09-30" \
  --data-urlencode "sort=starts-asc" \
  --data-urlencode "limit=20"
```

Pass a non-null `nextCursor` as `cursor` with the same filters and sort to get the next page.

## Retrieve an event and its version

```bash theme={null}
curl --request GET --fail-with-body --include \
  --url "$FLORAL_BASE_URL/workspaces/$FLORAL_WORKSPACE/events/42" \
  --header "Authorization: Bearer $FLORAL_TOKEN"
```

The strong `ETag` header and the `version` field carry the event's current version. You need it to finalise attendance.

## List participants

Participants are returned in registration order. Filter by registration state, attendance state, or CRM match status.

```bash theme={null}
curl --get --fail-with-body \
  --url "$FLORAL_BASE_URL/workspaces/$FLORAL_WORKSPACE/events/42/participants" \
  --header "Authorization: Bearer $FLORAL_TOKEN" \
  --data-urlencode "registrationState=REGISTERED" \
  --data-urlencode "limit=50"
```

Each participant has a UUID `id` and its own `version`. The `responses` object holds ordinary registration answers only.

## Read restricted answers

Answers to fields marked as restricted, such as dietary or accessibility needs, are never part of the participant resource. Only the event organiser or a workspace admin can read them, from a separate operation:

```bash theme={null}
curl --request GET --fail-with-body \
  --url "$FLORAL_BASE_URL/workspaces/$FLORAL_WORKSPACE/events/42/participants/0f8b6c1e-3a52-4d6e-9b7a-2c4e5f6a7b8c/restricted-responses" \
  --header "Authorization: Bearer $FLORAL_TOKEN"
```

Anyone else receives `403 FORBIDDEN`. Store these answers only as long as you need them for the event's logistics.

## Register a participant

Registration requires an `Idempotency-Key`. Answers are validated against the event's registration form.

```bash theme={null}
export REGISTRATION_KEY="01J5C7A2B9M4K8T1Q6D3R0V5XZ"

curl --request POST --fail-with-body --include \
  --url "$FLORAL_BASE_URL/workspaces/$FLORAL_WORKSPACE/events/42/participants" \
  --header "Authorization: Bearer $FLORAL_TOKEN" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: $REGISTRATION_KEY" \
  --data '{
    "name": "Ada Jensen",
    "email": "ada@example.com",
    "companyName": "Acme Nordic",
    "responses": { "session_track": "Operations" }
  }'
```

A successful registration returns `201` with a `Location` header and the participant's `ETag`. When the event is full and has a waitlist, the participant is created with `WAITLISTED` state and a `waitlistPosition`. When registration is closed, or the event is full without a waitlist, the operation returns `409 CONFLICT` and creates nothing.

## Update a participant

Send only the fields you want to change, with the participant's latest `ETag`. Sending `null` clears an optional field.

```bash theme={null}
export PARTICIPANT_ETAG='"v1.ZXhhbXBsZS1wYXJ0aWNpcGFudA"'

curl --request PATCH --fail-with-body --include \
  --url "$FLORAL_BASE_URL/workspaces/$FLORAL_WORKSPACE/events/42/participants/0f8b6c1e-3a52-4d6e-9b7a-2c4e5f6a7b8c" \
  --header "Authorization: Bearer $FLORAL_TOKEN" \
  --header "Content-Type: application/json" \
  --header "If-Match: $PARTICIPANT_ETAG" \
  --data '{"phone": "+45 12 34 56 78"}'
```

Only the event organiser or a workspace admin can change answers to restricted fields. A request from anyone else that includes a restricted field returns `403 FORBIDDEN` and changes nothing.

## Mark attendance

Mark up to 500 registered participants in one request. Marking requires an `Idempotency-Key` but no `If-Match`, so several people can check guests in at the same time.

```bash theme={null}
export CHECK_IN_KEY="01J5C7F4H2N6P9R3S8T1V5W0YA"

curl --request POST --fail-with-body \
  --url "$FLORAL_BASE_URL/workspaces/$FLORAL_WORKSPACE/events/42/attendance" \
  --header "Authorization: Bearer $FLORAL_TOKEN" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: $CHECK_IN_KEY" \
  --data '{
    "participantIds": ["0f8b6c1e-3a52-4d6e-9b7a-2c4e5f6a7b8c"],
    "state": "ATTENDED"
  }'
```

A batch is applied completely or not at all. It fails with `404 NOT_FOUND` if any ID does not belong to the event, with `409 INVALID_STATE` if any participant is not registered, and with `409 INVALID_STATE` after attendance has been finalised. The response lists the participants whose state changed and those that already had it.

## Finalise attendance

Finalising locks attendance for follow-up. It requires the event's latest `ETag` and an `Idempotency-Key`. List the registered participants who did not attend; everyone else who is still unmarked stays `UNKNOWN`.

```bash theme={null}
export EVENT_ETAG='"v1.ZXhhbXBsZS1ldmVudA"'
export FINALISE_KEY="01J5C7K8M1P4R7T0V3X6Z9B2DC"

curl --request POST --fail-with-body --include \
  --url "$FLORAL_BASE_URL/workspaces/$FLORAL_WORKSPACE/events/42/attendance/finalise" \
  --header "Authorization: Bearer $FLORAL_TOKEN" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: $FINALISE_KEY" \
  --header "If-Match: $EVENT_ETAG" \
  --data '{"noShowParticipantIds": []}'
```

Finalising an event that is already finalised returns `409 INVALID_STATE`.

## Correct finalised attendance

After finalisation, correct one participant at a time with a reason. Send the participant's latest `ETag`.

```bash theme={null}
export CORRECTION_KEY="01J5C7Q2S5U8W1Y4A7C0E3G6HJ"

curl --request POST --fail-with-body --include \
  --url "$FLORAL_BASE_URL/workspaces/$FLORAL_WORKSPACE/events/42/participants/0f8b6c1e-3a52-4d6e-9b7a-2c4e5f6a7b8c/attendance-correction" \
  --header "Authorization: Bearer $FLORAL_TOKEN" \
  --header "Content-Type: application/json" \
  --header "Idempotency-Key: $CORRECTION_KEY" \
  --header "If-Match: $PARTICIPANT_ETAG" \
  --data '{"state": "ATTENDED", "reason": "Signed in at the side entrance."}'
```

Floral keeps the earlier attendance record and marks it as superseded, so the correction history stays auditable.

Floral protects writes with two opaque values:

* Send a unique `Idempotency-Key` when an operation requires one. Retrying the identical request with the same key replays its result for 24 hours. Within that operation, reusing the key with different canonical input returns `409 IDEMPOTENCY_CONFLICT`.
* Send the latest strong `ETag` as `If-Match` when an operation changes an existing resource. A stale value returns `412 VERSION_CONFLICT`; a missing value returns `428 PRECONDITION_REQUIRED`.

Keep the quote characters around an `ETag`, and replace your saved value after every successful write. See [Reliability and retries](/developers/api/reliability) for the complete retry rules.
