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

# Writing events

> The rules POST and PATCH /v1/events enforce, and the refusals worth planning for.

The `POST` and `PATCH` endpoint pages document every field. This page covers the
behavior behind them — the parts that will surprise you if you assume a plain
CRUD resource.

## Creating

```bash theme={null}
curl -X POST "https://api.nowadays.ai/v1/events" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "name": "Annual Summit",
    "formattedLocations": [{ "city": "Austin" }],
    "eventDates": [{ "startDate": "2027-03-15", "endDate": "2027-03-17" }],
    "numPeople": 300
  }'
```

The response carries the new event's `id` and `grantedTo`:

```json theme={null}
{ "id": "3f2b8c1a-…", "grantedTo": 3 }
```

`grantedTo` is how many people can now see the event. Your key's user is one of
them; the rest are their approvers.

<Warning>
  **`grantedTo: 0` means the event exists but nobody can see it.** Enterprise
  events are private by default and visibility is derived from the creator's
  group memberships — so a key whose user belongs to no group produces an
  invisible event. It is not an error and the event is real; an administrator
  needs to add that user to a group. Check this value rather than assuming a
  `201` means the event is usable.
</Warning>

The organization comes from your key, so any `organizationId` in the body is
ignored.

## Updating

`PATCH /v1/events/{id}` takes only the fields you are changing.

```bash theme={null}
curl -X PATCH "https://api.nowadays.ai/v1/events/3f2b8c1a-…" \
  -H "x-api-key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "numPeople": 320, "otherNotes": null }'
```

Three rules govern every update:

<AccordionGroup>
  <Accordion title="Omitted means unchanged; null means cleared">
    A field you leave out is not touched. Sending `null` clears it. That
    distinction is deliberate — there is no way to accidentally blank a field by
    omitting it, and no way to clear one by guessing at an empty value.
  </Accordion>

  <Accordion title="All or nothing">
    If any field is rejected, **nothing is written** and the response lists every
    problem at once. A `400` therefore always means the event is untouched, so it
    is safe to correct and retry without checking what partially landed.
  </Accordion>

  <Accordion title="Some fields are derived, not writable">
    `location` is derived from `formattedLocations`, and `event_dates` from the
    union of your guestroom nights and agenda date ranges. Neither is accepted as
    input — send the inputs and the derived values follow.
  </Accordion>
</AccordionGroup>

### Editing the agenda

The agenda is edited by **operation**, not by replacement. Send
`agendaOperations` with `add`, `update` or `remove`, each addressed by a session
`id` from a prior `GET`:

```json theme={null}
{
  "agendaOperations": [
    { "op": "update", "sessionId": "a1b2…", "session": { "startTime": "09:30" } },
    { "op": "remove", "sessionId": "c3d4…" },
    {
      "op": "add",
      "session": {
        "title": "Closing keynote",
        "dates": ["2027-03-17"],
        "startTime": "16:00",
        "endTime": "17:00"
      }
    }
  ]
}
```

Replacing the whole agenda to change one session is both expensive and an easy
way to silently drop the ones you forgot, so the API does not offer it. An
unknown `sessionId` is an error rather than a silent no-op.

### Two refusals worth planning for

**A cancelled event cannot be edited.** You get `409`; reopen it in Nowadays
first.

**Shrinking the agenda dates is refused if any session would lose a date.** Also
`409`, with the affected sessions named in `orphanedSessions`:

```json theme={null}
{
  "message": "Those agenda dates would drop sessions…",
  "orphanedSessions": [
    {
      "sessionId": "a1b2…",
      "title": "Kickoff",
      "droppedDates": ["2027-03-14"],
      "fullyOrphaned": true
    }
  ]
}
```

The dashboard drops such sessions after an "are you sure" prompt. An API caller
has no equivalent prompt, so the API refuses instead — move or remove the
sessions deliberately, then retry.

## Limits

A single request is bounded so one call cannot monopolise the service:

| Field                                   | Limit                      |
| --------------------------------------- | -------------------------- |
| `agendaOperations`                      | 200 per request            |
| `formattedLocations`                    | 50 per request             |
| `decisionFactors`, `additionalServices` | 50 values each             |
| `accommodations`                        | 400 nights                 |
| `meetingRoomDates`                      | 50 ranges, each ≤ 366 days |
| Free-text fields                        | 1,000 characters           |
| `name`                                  | 100 characters             |

Exceeding one returns `400` with the offending field named, and — as always —
nothing is written.
