{
  "openapi": "3.1.0",
  "info": {
    "title": "Trackstage API",
    "version": "1.1.0",
    "summary": "Read and write your event's programme, speakers, submissions, custom fields and agenda — and get webhooks when any of it changes.",
    "description": "A complete REST API over an event: the event itself, sessions and abstracts, speakers and line-ups, CFP forms, custom fields, session files, speaker tasks, multi-round evaluation, the agenda, and signed outbound webhooks.\n\nEverything an organizer can do in the browser app, an integration can do here — and every response carries both this API's original field names and the names a Sessionboard client expects, so a migration is a base-URL change.\n\n---\n\n## Getting started\n\n### 1. Base URL\n\nEvery path below is relative to your deployment's Convex site URL — the one server, no regions to choose between:\n\n```\nhttps://keen-eagle-41.convex.site\n```\n\n### 2. Get a key\n\n**Account settings → API & MCP → Create key.** The key (`sb_live_…`) is shown **once**, at creation — copy it then. Keys are revocable from that same screen, and a revoked key stops working immediately. Optionally pick a scope set when you create it (see below); a key created without one is unrestricted within its owner's own permissions.\n\n### 3. Make a call\n\n```bash\ncurl -s \"https://keen-eagle-41.convex.site/v1/events\" \\\n  -H \"Authorization: Bearer sb_live_…\"\n```\n\nOr, byte-for-byte compatible with a Sessionboard client:\n\n```bash\ncurl -s \"https://keen-eagle-41.convex.site/v1/event/ai-summit-2026/sessions\" \\\n  -H \"x-access-token: sb_live_…\"\n```\n\nPrefer to look before you sign up? The token `demo-api-token` reads the demo events and answers **403** on every write.\n\n---\n\n## Authentication\n\nTwo header forms are accepted, interchangeably, on every authenticated endpoint:\n\n| Header | Form | Notes |\n| --- | --- | --- |\n| `Authorization` | `Bearer sb_live_…` | The scheme this API has always used. |\n| `x-access-token` | `sb_live_…` | Sessionboard's header, so their clients work unchanged. |\n\nA key resolves to a **user**, and every request re-runs the same workspace-membership authorization the browser app runs — including per-member event scoping. A key can therefore never reach an event its owner cannot, and a leaked key is bounded by a real permission model rather than by an organization boundary.\n\n**Roles.** Some operations need more than membership: publishing or unpublishing the agenda, deleting or restoring a session, deleting an event, a form or a task, and every webhook write require the **admin** role on the event. A member without it gets a 403 that says so.\n\n### Scopes\n\nA key may declare a scope set. Unset means *unrestricted within the owner's permissions*; setting scopes can only ever **narrow** that, never widen it. Each operation below names the scope it enforces, both in prose and as an `x-required-scope` extension.\n\n| Scope | Grants |\n| --- | --- |\n| `read:events` | Events, agenda, settings, forms, tasks, webhooks. |\n| `read:sessions` | Sessions, abstracts, submissions, session files, evaluation. |\n| `read:contacts` | Speakers, session line-ups, evaluators. |\n| `write:sessions` | Session create/update/delete/restore/bulk, files, participants, evaluation plans. |\n| `write:contacts` | Speaker create/update/delete, evaluator management. |\n| `write:fields` | Custom-field definitions and CFP forms. |\n| `write:metadata` | Tracks, rooms, tags, formats, levels, languages, statuses. |\n| `write:events` | Event CRUD, agenda publish/unpublish, tasks, webhooks. |\n\nA 403 always names the missing scope, e.g. `This token lacks the \\`write:sessions\\` scope.`\n\n### Endpoints that need no credential\n\n- `GET /v1/event/{eventRef}/schedule.ics` — calendar clients subscribe by URL and cannot send headers.\n- `POST /v1/_echo` — the signature-verifying test sink.\n\n### AI agents: MCP and OAuth\n\nThis is the REST surface. Agents have a second, separate one: a full **MCP server at `/mcp`**, authenticated with **OAuth 2.1 + PKCE** (discovery at `/.well-known/oauth-protected-resource`) rather than with an API key — connect it from Claude, Cursor or any MCP client and the same authorization rules apply. An `sb_live_…` key also works there as a bearer token for non-interactive clients. See [the MCP reference](/docs/mcp).\n\n---\n\n## Conventions\n\n### Addressing an event\n\n`{eventRef}` accepts the event's **slug** or its **id**, everywhere. `/v1/event/ai-summit-2026/sessions` and `/v1/event/k97abc…/sessions` are the same endpoint — the slug form is the one you want in a shell history. Forms take their slug too (`/forms/cfp`).\n\n### Pagination\n\nEvery list takes `page` (1-based) and `pageSize` (default 25, max 100; `page_size` is accepted as an alias). Every paginated response carries the same array under **both** `data` and `results`, and pagination counts in **both** spellings:\n\n```json\n{\n  \"data\": [ … ],\n  \"results\": [ … ],\n  \"pagination\": {\n    \"currentPage\": 1, \"pageSize\": 25, \"totalPages\": 4, \"totalResults\": 87,\n    \"current_page\": 1, \"page_size\": 25, \"total_pages\": 4, \"total_results\": 87\n  }\n}\n```\n\nSo a client written against either convention works, and no endpoint makes you check which one you are on. Single-resource responses are `{ \"data\": { … } }`.\n\n### Errors\n\nEvery failure has the same shape:\n\n```json\n{\n  \"error\": \"This session changed since you fetched it (now 2026-08-11T09:12:44.001Z). Re-fetch and retry.\",\n  \"code\": \"ConflictError\",\n  \"message\": \"This session changed since you fetched it (now 2026-08-11T09:12:44.001Z). Re-fetch and retry.\",\n  \"status\": 409\n}\n```\n\n`error` and `message` are the same organizer-readable sentence — `error` is where this API has always put it, `message` is where Sessionboard clients look. `code` is the machine-readable name:\n\n| Status | `code` | When |\n| --- | --- | --- |\n| 400 | `BadRequestError` | The body or parameters are invalid; the message says what. |\n| 401 | `UnauthorizedError` | Missing or invalid key. |\n| 403 | `ForbiddenError` | Valid key, but missing scope, role, or workspace access — including the read-only demo token attempting a write. |\n| 404 | `NotFoundError` | No such event, resource or endpoint. A mistyped path answers with the nearest real routes. |\n| 405 | `MethodNotAllowedError` | Right path, wrong verb. |\n| 409 | `ConflictError` | Stale `updated_at` — someone else edited first. |\n| 413 | `PayloadTooLargeError` | Over the 50 MB simple-upload ceiling. |\n| 429 | `TooManyRequestsError` | Rate limited; wait `Retry-After` seconds. |\n| 500 | `InternalServerError` | Ours, not yours. |\n\nMessages are written for the person reading them, never stack traces.\n\n### Rate limits\n\n100 requests / 15 minutes **per key, per bucket**. The buckets are `entity_reads`, `session_writes`, `field_writes`, `metadata_writes` and `event_writes`, so a bulk import cannot starve your dashboard's reads. Each operation names its bucket below (and carries it as `x-rate-limit-bucket`).\n\n| Header | Meaning |\n| --- | --- |\n| `RateLimit-Limit` | Requests allowed in the window. |\n| `RateLimit-Remaining` | Requests left. |\n| `RateLimit-Reset` | Unix seconds at which the window resets. |\n| `Retry-After` | On a 429 only: seconds to wait. |\n\n### Times\n\nISO-8601 in responses. Requests accept ISO-8601 **or** epoch milliseconds, anywhere a time is taken. Legacy epoch-millisecond fields (`startTime`, `endTime`, `submittedAt`, `decidedAt`, …) are still returned alongside the ISO ones and will not be removed.\n\n### Optimistic concurrency\n\nSend the `updated_at` you last read on `PUT /sessions/{id}`. If someone edited the session in between, the call answers **409** with the current value instead of silently clobbering their work; re-read and retry.\n\n### `expand`\n\nComma-separated on session reads: `expand=files` inlines the session's attachments, `expand=deleted` lets a soft-deleted session be read.\n\n### Soft deletes\n\n`DELETE /sessions/{id}` and `DELETE /statuses/{id}` archive rather than destroy — the row leaves every listing, reads 404, and comes back intact via the matching `/restore`. `DELETE /events/{ref}` is the one exception: it runs the full cascade and is not recoverable.\n\n---\n\n### Custom fields\n\nA custom field and a CFP form question are the same object. `GET /v1/event/{eventRef}/fields` returns the definitions (with `internal_name`, type, options and whether the field holds PII); every session carries its answers as `custom_fields[]` (labelled, with a lossless `value_raw`) and as a raw `answers` map; `PUT /v1/event/{eventRef}/sessions/{sessionId}/fields` writes them. Creating a field through `POST /fields/create` adds the question to the form builder and to the public submission form.\n\n### Webhooks\n\nRegister an endpoint with `POST /v1/webhooks`. Every delivery POSTs `{ data, metadata }` and carries:\n\n| Header | Meaning |\n| --- | --- |\n| `Trackstage-Signature` | `t=<unix-seconds>,v1=<hex>` — HMAC-SHA256 of `\"{t}.{body}\"` keyed with the endpoint's `whsec_…` secret. |\n| `Trackstage-Event` | The event type. |\n| `Trackstage-Delivery` | Unique delivery id, for idempotency. |\n\nVerify the signature before trusting a payload, and reject timestamps outside your tolerance to prevent replay. Failed deliveries retry five times with exponential backoff (1s, 5s, 25s, 125s) and the full attempt log — including the exact signed body — is readable at `GET /v1/webhooks/{webhookId}/deliveries`.\n\n**Verifying a delivery** (Node, no dependencies):\n\n```js\nimport { createHmac, timingSafeEqual } from \"node:crypto\"\n\nexport function verify(rawBody, header, secret, toleranceSeconds = 300) {\n  const m = /t=(\\d+),v1=([0-9a-f]+)/.exec(header ?? \"\")\n  if (!m) return false\n  const [, t, signature] = m\n  if (Math.abs(Date.now() / 1000 - Number(t)) > toleranceSeconds) return false // replay\n  const expected = createHmac(\"sha256\", secret).update(`${t}.${rawBody}`).digest(\"hex\")\n  const a = Buffer.from(expected), b = Buffer.from(signature)\n  return a.length === b.length && timingSafeEqual(a, b)\n}\n```\n\nSign over the **raw body bytes**, before any JSON parsing — re-serialising changes the bytes and the signature will not match.\n\nNot sure your receiver is right? Point a webhook at `POST /v1/_echo?secret=whsec_…`. That sink recomputes the HMAC itself and answers 200 **only** when the signature verifies, so a green delivery in the log is proof, not a guess.\n\n**Event types**\n\n| Event | Fires when |\n| --- | --- |\n| `submission.created` | A CFP submission arrived. |\n| `submission.updated` | A submission's details or status changed. |\n| `session.created` | A programme session was created. |\n| `session.updated` | A session's details changed. |\n| `session.deleted` | A session was soft-deleted. |\n| `session.restored` | A soft-deleted session was restored. |\n| `session.scheduled` | A session was given a room and a slot. |\n| `session.unscheduled` | A session was taken off the timetable. |\n| `decision.committed` | An accept or decline queue was committed and the emails went out. |\n| `agenda.published` | The public programme went live. |\n| `speaker.created` | Someone was added to the roster. |\n| `speaker.updated` | A speaker's profile or workflow status changed. |\n| `file.uploaded` | A file was attached to a session. |\n| `file.deleted` | A session file was removed. |\n| `webhook.test` | A test delivery you triggered yourself. |\n\nSubscribe to `[\"*\"]` for all of them. Scope an endpoint to one event with `\"event\": \"ai-summit-2026\"`, or omit it for every event in the workspace.\n\n---\n\n### Uploading session files\n\nTwo flows, same resource. Use the simple one until you hit its ceiling.\n\n**Simple — one request, up to 50 MB.** `multipart/form-data`, field name `file`:\n\n```bash\ncurl -X POST \"$BASE/v1/event/ai-summit-2026/sessions/$SID/files/upload\" \\\n  -H \"Authorization: Bearer sb_live_…\" \\\n  -F \"file=@keynote-slides.pptx\" \\\n  -F \"title=Keynote deck (final)\"\n```\n\nSize and MIME type are read from the bytes. Over 50 MB answers **413** and tells you to use the two-phase flow.\n\n**Two-phase — for anything larger.** Three calls:\n\n1. `POST …/sessions/{sessionId}/files` with `{ \"filename\": \"…\" }` → returns an id and an `upload` block (`url`, `method`, `headers`).\n2. `PUT` the raw bytes to that `upload.url`. Unlike a presigned S3 URL this leg is authenticated with **your ordinary API key**, so no credential is ever embedded in a URL that can leak through logs or referrers. Re-PUTting replaces the pending bytes.\n3. `POST …/files/{fileId}/complete` → promotes the blob into a real attachment and returns it. Completing with no bytes received answers 400.\n\n**Replacing a file** is the same three steps starting from `POST …/files/{fileId}/replace`; the file group's version is bumped and the previous version retired when the replacement completes. `PUT …/files/{fileId}` changes the title or the participant it is assigned to without touching bytes, and `DELETE` soft-deletes.\n\n---\n\n### The calendar feed\n\n`GET /v1/event/{eventRef}/schedule.ics` is an RFC 5545 feed of the published programme — accepted, scheduled sessions of an event whose agenda has been published. It takes **no credential**, because calendar clients subscribe by URL and cannot send headers; paste it into Google Calendar, Apple Calendar or Outlook as a subscription and it stays in step with the board.\n\n---\n\n### Migrating from Sessionboard\n\nChange the base URL and the event id, and keep your code. Their paths, their `x-access-token` header, their `filters`/`sort`/`expand` search bodies, their `results` + `pagination` envelope, their status enum, their `custom_fields[]` shape and their 4xx codes are all served as-is. What is additive on our side: `data` alongside `results`, snake_case *and* camelCase pagination, `value_raw` on every custom field, slugs as event references, and the endpoints their API does not have at all — event CRUD, forms, tasks, evaluation, participants and API-managed webhooks.",
    "license": {
      "name": "MIT",
      "identifier": "MIT"
    },
    "contact": {
      "name": "Trackstage",
      "url": "https://github.com/markokraemer/trackstage"
    }
  },
  "servers": [
    {
      "url": "https://keen-eagle-41.convex.site",
      "description": "Your deployment's Convex site URL."
    }
  ],
  "security": [
    {
      "ApiKeyHeader": []
    },
    {
      "BearerToken": []
    }
  ],
  "tags": [
    {
      "name": "Events",
      "description": "Full CRUD over the event itself: list, read, create, update, delete. Sessionboard's API reads events only — everything but `GET /v1/events` is ours."
    },
    {
      "name": "Sessions",
      "description": "Read sessions, abstracts and submissions, and read a session's line-up. Writes are in **Session Writes** below."
    },
    {
      "name": "Session Writes",
      "description": "Create, update, soft-delete, restore and bulk-edit sessions, and attach or detach speakers. Requires `write:sessions`."
    },
    {
      "name": "Session Files",
      "description": "Attachments on a session — slides, handouts, anything a speaker uploads. Reads need `read:sessions`; every write needs `write:sessions`."
    },
    {
      "name": "Speakers",
      "description": "The event's people and the sessions they are on. Reads need `read:contacts`, writes `write:contacts`."
    },
    {
      "name": "Forms",
      "description": "The call-for-speakers forms themselves — list, read, create, update, delete. A form's questions ARE this event's custom-field definitions, so editing one here changes the public submission page. Requires `write:fields` to change."
    },
    {
      "name": "Tasks",
      "description": "What each speaker still owes the organizer: headshots, slides, profile completion. `GET /tasks?status=open` is the outstanding-tasks dashboard as an API call. Requires `write:events` to change."
    },
    {
      "name": "Evaluation",
      "description": "Multi-round review: plans (criteria + pool), evaluators (with their magic review links and per-evaluator assignment), and the individual scorecards behind every average."
    },
    {
      "name": "Agenda",
      "description": "The timetable, its conflicts, and the publish gate."
    },
    {
      "name": "Event Settings",
      "description": "Read the field definitions and the value lists a session's metadata comes from: tracks, rooms, tags, formats, levels, languages, statuses. Writes are in the two tags below."
    },
    {
      "name": "Field Writes",
      "description": "Define custom fields. In this product a custom field IS a CFP form question, so changes show up in the form builder and on the public form. Requires `write:fields`."
    },
    {
      "name": "Metadata Writes",
      "description": "Create, rename, delete and restore tracks, rooms, value lists and session statuses. Requires `write:metadata`."
    },
    {
      "name": "Webhooks",
      "description": "Signed, retried HTTP callbacks so you never have to poll. Requires `write:events` to manage."
    },
    {
      "name": "Calendar",
      "description": "The public .ics subscription feed."
    }
  ],
  "paths": {
    "/v1/_echo": {
      "post": {
        "operationId": "echoWebhookDelivery",
        "tags": [
          "Webhooks"
        ],
        "summary": "Signature-verifying echo sink",
        "description": "Test target for webhook deliveries. Pass the endpoint's signing secret as `?secret=` and the sink recomputes the HMAC over the exact body: it answers 200 only when the signature verifies, and 401 otherwise. Point a webhook here to prove end-to-end delivery and signing without standing up a server.\n\n**Authentication** — none required. This endpoint is deliberately open (see the description above); sending a key anyway is harmless.",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/secret"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EchoResult"
                },
                "example": {
                  "received": true,
                  "verified": true,
                  "event": "session.updated",
                  "delivery": "k87abc…"
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": []
      }
    },
    "/v1/event/{eventRef}/agenda": {
      "get": {
        "operationId": "getAgenda",
        "tags": [
          "Agenda"
        ],
        "summary": "Get the agenda",
        "description": "The whole timetable in one read: rooms, tracks, every placement, everything still unscheduled, and the live conflict list (double-booked rooms and speakers).\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.",
        "x-required-scope": "read:events",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AgendaEnvelope"
                },
                "example": {
                  "data": {
                    "conflicts": [],
                    "event": {
                      "_id": "j976eyym787qhaq02v0nea4k7x8c879q",
                      "agenda_published_at": "2026-08-06T19:27:45.331Z",
                      "background_url": null,
                      "created_at": "2026-08-11T19:27:45.331Z",
                      "description": "Two days for the people building AI systems that have to work on Monday morning. Practitioner talks on evaluation, agents, retrieval, inference infrastructure and the product decisions in between — no keynote fluff, no vendor pitches.",
                      "endsAt": 1791939600000,
                      "ends_at": "2026-10-14T01:00:00.000Z",
                      "features": {
                        "custom_fields": true,
                        "translated_fields": false,
                        "webhooks": true
                      },
                      "id": "j976eyym787qhaq02v0nea4k7x8c879q",
                      "logo_url": null,
                      "name": "AI Engineer Summit 2026",
                      "organization_id": "mn7fs8btg5szyhbkqdfhtd4xmn8c8xhg",
                      "portal_settings": {
                        "allow_submission_edits": true,
                        "always_show_tasks": false,
                        "extend_task_deadlines": true
                      },
                      "public_url": "/e/ai-engineer/ai-summit-2026",
                      "slug": "ai-summit-2026",
                      "startsAt": 1791820800000,
                      "starts_at": "2026-10-12T16:00:00.000Z",
                      "timezone": "America/Los_Angeles",
                      "type": "Conference",
                      "venue": "Moscone West, San Francisco",
                      "websiteUrl": "https://example.com/ai-summit-2026",
                      "website_url": "https://example.com/ai-summit-2026"
                    },
                    "published": true,
                    "published_at": "2026-08-06T19:27:45.331Z",
                    "rooms": [
                      {
                        "capacity": 300,
                        "id": "js7bf7gcc7h75dees2qgsk7wks8c8yja",
                        "name": "Main Stage",
                        "order": 0
                      },
                      {
                        "capacity": 80,
                        "id": "js7dwszc5hx3y92bmf1686s96x8c9g9h",
                        "name": "Workshop Room",
                        "order": 1
                      }
                    ],
                    "scheduled": [
                      {
                        "duration_minutes": 45,
                        "ends_at": "2026-10-12T09:45:00.000Z",
                        "id": "k57frjzyeeeb4dpf4gadr95d018c9ty9",
                        "is_public": true,
                        "room_id": "js7bf7gcc7h75dees2qgsk7wks8c8yja",
                        "starts_at": "2026-10-12T09:00:00.000Z",
                        "title": "Structured output without the sadness",
                        "track_id": "kd70s9jv39zmvkarkyrjcbk14x8c8g9d"
                      },
                      {
                        "duration_minutes": 45,
                        "ends_at": "2026-10-12T09:45:00.000Z",
                        "id": "k577pznhjcx1fhk73b9vme1rvd8c9a0n",
                        "is_public": true,
                        "room_id": "js7dwszc5hx3y92bmf1686s96x8c9g9h",
                        "starts_at": "2026-10-12T09:00:00.000Z",
                        "title": "Cost modelling for inference-heavy products",
                        "track_id": "kd73edp90maypnbd8ee3hjx6eh8c9xh4"
                      }
                    ],
                    "totals": {
                      "conflicts": 0,
                      "scheduled": 9,
                      "unscheduled": 0
                    },
                    "tracks": [
                      {
                        "color": "#2F5CE0",
                        "id": "kd70s9jv39zmvkarkyrjcbk14x8c8g9d",
                        "name": "AI Engineering",
                        "order": 0
                      },
                      {
                        "color": "#1E9E6B",
                        "id": "kd73edp90maypnbd8ee3hjx6eh8c9xh4",
                        "name": "Product",
                        "order": 1
                      }
                    ],
                    "unscheduled": []
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/agenda/publish": {
      "post": {
        "operationId": "publishAgenda",
        "tags": [
          "Agenda"
        ],
        "summary": "Publish the agenda",
        "description": "Opens the public programme. Until this is called the public pages render “Schedule coming soon” however much is scheduled internally. Requires the admin role.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `event_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:events",
        "x-rate-limit-bucket": "event_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventEnvelope"
                },
                "example": {
                  "data": {
                    "_id": "j97anpvjehq8w0at0d7zqef8418c9h51",
                    "agenda_published_at": null,
                    "background_url": null,
                    "created_at": "2026-08-11T13:10:05.999Z",
                    "description": "A single-track day for the people who maintain design systems, and everyone who has to live with them.",
                    "endsAt": 1793919600000,
                    "ends_at": "2026-11-05T23:00:00.000Z",
                    "features": {
                      "custom_fields": true,
                      "translated_fields": false,
                      "webhooks": true
                    },
                    "id": "j97anpvjehq8w0at0d7zqef8418c9h51",
                    "logo_url": null,
                    "name": "Design Systems Day",
                    "organization_id": "mn7fs8btg5szyhbkqdfhtd4xmn8c8xhg",
                    "portal_settings": {
                      "allow_submission_edits": true,
                      "always_show_tasks": false,
                      "extend_task_deadlines": true
                    },
                    "public_url": "/e/design-systems-day",
                    "slug": "design-systems-day",
                    "startsAt": 1793887200000,
                    "starts_at": "2026-11-05T14:00:00.000Z",
                    "timezone": "America/New_York",
                    "type": "Meetup",
                    "venue": "Brooklyn Expo Center, New York",
                    "website_url": null
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/agenda/unpublish": {
      "post": {
        "operationId": "unpublishAgenda",
        "tags": [
          "Agenda"
        ],
        "summary": "Unpublish the agenda",
        "description": "Takes the public programme back down. Requires the admin role.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `event_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:events",
        "x-rate-limit-bucket": "event_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventEnvelope"
                },
                "example": {
                  "data": {
                    "_id": "j97anpvjehq8w0at0d7zqef8418c9h51",
                    "agenda_published_at": null,
                    "background_url": null,
                    "created_at": "2026-08-11T13:10:05.999Z",
                    "description": "A single-track day for the people who maintain design systems, and everyone who has to live with them.",
                    "endsAt": 1793919600000,
                    "ends_at": "2026-11-05T23:00:00.000Z",
                    "features": {
                      "custom_fields": true,
                      "translated_fields": false,
                      "webhooks": true
                    },
                    "id": "j97anpvjehq8w0at0d7zqef8418c9h51",
                    "logo_url": null,
                    "name": "Design Systems Day",
                    "organization_id": "mn7fs8btg5szyhbkqdfhtd4xmn8c8xhg",
                    "portal_settings": {
                      "allow_submission_edits": true,
                      "always_show_tasks": false,
                      "extend_task_deadlines": true
                    },
                    "public_url": "/e/design-systems-day",
                    "slug": "design-systems-day",
                    "startsAt": 1793887200000,
                    "starts_at": "2026-11-05T14:00:00.000Z",
                    "timezone": "America/New_York",
                    "type": "Meetup",
                    "venue": "Brooklyn Expo Center, New York",
                    "website_url": null
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/evaluation-plans": {
      "get": {
        "operationId": "listEvaluationPlans",
        "tags": [
          "Evaluation"
        ],
        "summary": "List evaluation plans",
        "description": "Every review round on the event with its criteria, its pool, how many evaluations are expected, how many are in, and the weighted average score so far.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.",
        "x-required-scope": "read:sessions",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          },
          {
            "$ref": "#/components/parameters/status"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EvaluationPlansPage"
                },
                "example": {
                  "data": [
                    {
                      "assigned_count": 16,
                      "average_score": 4.3,
                      "blind": false,
                      "completed_count": 10,
                      "completion_pct": 63,
                      "created_at": "2026-08-11T19:27:45.331Z",
                      "criteria": [
                        {
                          "id": "overall",
                          "label": "Overall",
                          "options": null,
                          "type": "numeric",
                          "weight": 1
                        },
                        {
                          "id": "relevance",
                          "label": "Relevance",
                          "options": null,
                          "type": "numeric",
                          "weight": 1
                        }
                      ],
                      "due_at": "2026-09-26T00:00:00.000Z",
                      "evaluator_count": 2,
                      "id": "kn78gh8vhgya5k09htqyz7cct58c8k2k",
                      "name": "Round 1 — Programme Committee",
                      "opens_at": null,
                      "outstanding_count": 6,
                      "recused_count": 0,
                      "round": 1,
                      "scored_count": 10,
                      "status": "open",
                      "submission_count": 8,
                      "submission_ids": [
                        "k57c8t51z27m64nqk6mwnqae5d8c9ffq",
                        "k57f9gyjryn3d1d7996rdtqm5d8c8zb5"
                      ]
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 1,
                    "page_size": 1,
                    "totalPages": 3,
                    "totalResults": 3,
                    "total_pages": 3,
                    "total_results": 3
                  },
                  "results": [
                    {
                      "assigned_count": 16,
                      "average_score": 4.3,
                      "blind": false,
                      "completed_count": 10,
                      "completion_pct": 63,
                      "created_at": "2026-08-11T19:27:45.331Z",
                      "criteria": [
                        {
                          "id": "overall",
                          "label": "Overall",
                          "options": null,
                          "type": "numeric",
                          "weight": 1
                        },
                        {
                          "id": "relevance",
                          "label": "Relevance",
                          "options": null,
                          "type": "numeric",
                          "weight": 1
                        }
                      ],
                      "due_at": "2026-09-26T00:00:00.000Z",
                      "evaluator_count": 2,
                      "id": "kn78gh8vhgya5k09htqyz7cct58c8k2k",
                      "name": "Round 1 — Programme Committee",
                      "opens_at": null,
                      "outstanding_count": 6,
                      "recused_count": 0,
                      "round": 1,
                      "scored_count": 10,
                      "status": "open",
                      "submission_count": 8,
                      "submission_ids": [
                        "k57c8t51z27m64nqk6mwnqae5d8c9ffq",
                        "k57f9gyjryn3d1d7996rdtqm5d8c8zb5"
                      ]
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/evaluation-plans/{planId}": {
      "get": {
        "operationId": "getEvaluationPlan",
        "tags": [
          "Evaluation"
        ],
        "summary": "Get an evaluation plan",
        "description": "The plan plus every evaluator (with their assignment, their progress and their review link) and every submission in the pool with its average score.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:sessions",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/planId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EvaluationPlanEnvelope"
                },
                "example": {
                  "data": {
                    "assigned_count": 16,
                    "average_score": 4.3,
                    "blind": false,
                    "completed_count": 10,
                    "completion_pct": 63,
                    "created_at": "2026-08-11T19:27:45.331Z",
                    "criteria": [
                      {
                        "id": "overall",
                        "label": "Overall",
                        "options": null,
                        "type": "numeric",
                        "weight": 1
                      },
                      {
                        "id": "relevance",
                        "label": "Relevance",
                        "options": null,
                        "type": "numeric",
                        "weight": 1
                      }
                    ],
                    "due_at": "2026-09-26T00:00:00.000Z",
                    "evaluator_count": 2,
                    "evaluators": [
                      {
                        "assigned_count": 8,
                        "assigned_submission_ids": [
                          "k57c8t51z27m64nqk6mwnqae5d8c9ffq",
                          "k57f9gyjryn3d1d7996rdtqm5d8c8zb5"
                        ],
                        "completed_count": 6,
                        "created_at": "2026-08-11T19:27:45.331Z",
                        "custom_assignment": false,
                        "email": "alex.rivera@example.com",
                        "id": "kx780cw1zr9eqkpvghkmf5rfdh8c87bf",
                        "last_reminded_at": null,
                        "name": "Alex Rivera",
                        "outstanding_count": 2,
                        "plan_id": "kn78gh8vhgya5k09htqyz7cct58c8k2k",
                        "recused_count": 0,
                        "review_path": "/review/demo-eval-alex",
                        "token": "demo-eval-alex"
                      },
                      {
                        "assigned_count": 8,
                        "assigned_submission_ids": [
                          "k57c8t51z27m64nqk6mwnqae5d8c9ffq",
                          "k57f9gyjryn3d1d7996rdtqm5d8c8zb5"
                        ],
                        "completed_count": 4,
                        "created_at": "2026-08-11T19:27:45.331Z",
                        "custom_assignment": false,
                        "email": "sam.okafor@example.com",
                        "id": "kx7ack09fm2e60vna3rzdh211d8c87vb",
                        "last_reminded_at": null,
                        "name": "Sam Okafor",
                        "outstanding_count": 4,
                        "plan_id": "kn78gh8vhgya5k09htqyz7cct58c8k2k",
                        "recused_count": 0,
                        "review_path": "/review/demo-eval-sam",
                        "token": "demo-eval-sam"
                      }
                    ],
                    "id": "kn78gh8vhgya5k09htqyz7cct58c8k2k",
                    "name": "Round 1 — Programme Committee",
                    "opens_at": null,
                    "outstanding_count": 6,
                    "recused_count": 0,
                    "round": 1,
                    "scored_count": 10,
                    "status": "open",
                    "submission_count": 8,
                    "submission_ids": [
                      "k57c8t51z27m64nqk6mwnqae5d8c9ffq",
                      "k57f9gyjryn3d1d7996rdtqm5d8c8zb5"
                    ],
                    "submissions": [
                      {
                        "average_score": 4.25,
                        "completed_count": 2,
                        "id": "k57c8t51z27m64nqk6mwnqae5d8c9ffq",
                        "recused_count": 0,
                        "status": "pending",
                        "title": "Shipping LLM features when latency is the product"
                      },
                      {
                        "average_score": 4,
                        "completed_count": 2,
                        "id": "k57f9gyjryn3d1d7996rdtqm5d8c8zb5",
                        "recused_count": 0,
                        "status": "pending",
                        "title": "Vector databases at ten billion embeddings"
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "put": {
        "operationId": "updateEvaluationPlan",
        "tags": [
          "Evaluation"
        ],
        "summary": "Update an evaluation plan",
        "description": "Partial update — rename it, move the window, widen the pool, or set `status: \"closed\"` to end the round.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `event_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:sessions",
        "x-rate-limit-bucket": "event_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/planId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EvaluationPlanWriteBody"
              },
              "example": {
                "status": "closed"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EvaluationPlanEnvelope"
                },
                "example": {
                  "data": {
                    "assigned_count": 16,
                    "average_score": 4.3,
                    "blind": false,
                    "completed_count": 10,
                    "completion_pct": 63,
                    "created_at": "2026-08-11T13:10:05.999Z",
                    "criteria": [
                      {
                        "id": "overall",
                        "label": "Overall",
                        "options": null,
                        "type": "numeric",
                        "weight": 1
                      },
                      {
                        "id": "relevance",
                        "label": "Relevance",
                        "options": null,
                        "type": "numeric",
                        "weight": 1
                      }
                    ],
                    "due_at": "2026-09-26T00:00:00.000Z",
                    "evaluator_count": 2,
                    "id": "kn74xm0r2pddem9a64nmjpb8ex8c84tk",
                    "name": "Round 1 — Programme Committee",
                    "opens_at": null,
                    "outstanding_count": 6,
                    "recused_count": 0,
                    "round": 1,
                    "scored_count": 10,
                    "status": "open",
                    "submission_count": 8,
                    "submission_ids": [
                      "k570fhnr7rfajzm9chz9pzpw3s8c90bg",
                      "k5748as8c8s7f6n4wcka9rtvsd8c94dp"
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "delete": {
        "operationId": "deleteEvaluationPlan",
        "tags": [
          "Evaluation"
        ],
        "summary": "Delete an evaluation plan",
        "description": "Deletes the round, its evaluators and the scores they submitted. The submissions themselves are untouched.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `event_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:sessions",
        "x-rate-limit-bucket": "event_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/planId"
          }
        ],
        "responses": {
          "204": {
            "description": "No content.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/evaluation-plans/create": {
      "post": {
        "operationId": "createEvaluationPlan",
        "tags": [
          "Evaluation"
        ],
        "summary": "Create an evaluation plan",
        "description": "Stands up a review round: a name, a round number, the criteria evaluators score against, and the submissions in the pool. Criteria may be `numeric` (1–5, weightable), `select` or `text`.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `event_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:sessions",
        "x-rate-limit-bucket": "event_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EvaluationPlanWriteBody"
              },
              "example": {
                "name": "Round 1 — technical review",
                "round": 1,
                "blind": true,
                "due_at": "2026-07-01T23:59:00.000Z",
                "criteria": [
                  {
                    "label": "Relevance",
                    "type": "numeric",
                    "weight": 2
                  },
                  {
                    "label": "Speaker experience",
                    "type": "numeric"
                  },
                  {
                    "label": "Recommendation",
                    "type": "select",
                    "options": [
                      "Accept",
                      "Waitlist",
                      "Decline"
                    ]
                  }
                ],
                "submission_ids": [
                  "k17abc…",
                  "k17def…"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EvaluationPlanEnvelope"
                },
                "example": {
                  "data": {
                    "assigned_count": 16,
                    "average_score": 4.3,
                    "blind": false,
                    "completed_count": 10,
                    "completion_pct": 63,
                    "created_at": "2026-08-11T13:10:05.999Z",
                    "criteria": [
                      {
                        "id": "overall",
                        "label": "Overall",
                        "options": null,
                        "type": "numeric",
                        "weight": 1
                      },
                      {
                        "id": "relevance",
                        "label": "Relevance",
                        "options": null,
                        "type": "numeric",
                        "weight": 1
                      }
                    ],
                    "due_at": "2026-09-26T00:00:00.000Z",
                    "evaluator_count": 2,
                    "id": "kn74xm0r2pddem9a64nmjpb8ex8c84tk",
                    "name": "Round 1 — Programme Committee",
                    "opens_at": null,
                    "outstanding_count": 6,
                    "recused_count": 0,
                    "round": 1,
                    "scored_count": 10,
                    "status": "open",
                    "submission_count": 8,
                    "submission_ids": [
                      "k570fhnr7rfajzm9chz9pzpw3s8c90bg",
                      "k5748as8c8s7f6n4wcka9rtvsd8c94dp"
                    ]
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/evaluations": {
      "get": {
        "operationId": "listEvaluations",
        "tags": [
          "Evaluation"
        ],
        "summary": "List submitted evaluations",
        "description": "Individual scorecards — per criterion scores, free-text answers, the comment, and whether the evaluator recused themselves. Filter by `plan_id`, `session_id` or `evaluator_id`. This is the raw data behind any scoring report you want to build yourself.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.",
        "x-required-scope": "read:sessions",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          },
          {
            "$ref": "#/components/parameters/plan_id"
          },
          {
            "$ref": "#/components/parameters/session_id"
          },
          {
            "$ref": "#/components/parameters/evaluator_id"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EvaluationsPage"
                },
                "example": {
                  "data": [
                    {
                      "comment": "Solid.",
                      "completed_at": "2026-08-11T19:29:03.507Z",
                      "created_at": "2026-08-11T19:29:03.507Z",
                      "evaluator_email": "verifier@example.com",
                      "evaluator_id": "kx7110kst49nj4qm4m1844k1qh8c89zc",
                      "id": "ks7cv767171mgyr1h7kyz68exn8c9csv",
                      "plan_id": "kn7dkvygf1n362yd6sk197f26n8c9t4v",
                      "plan_name": "Verify Plan",
                      "recusal_reason": null,
                      "recused": false,
                      "round": 3,
                      "scores": {
                        "overall": 4
                      },
                      "session_id": "k575rnyz47j4d4qnh0fh3mh5rh8c9mm8",
                      "session_title": "Verification Talk (edited)",
                      "values": {}
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 1,
                    "page_size": 1,
                    "totalPages": 11,
                    "totalResults": 11,
                    "total_pages": 11,
                    "total_results": 11
                  },
                  "results": [
                    {
                      "comment": "Solid.",
                      "completed_at": "2026-08-11T19:29:03.507Z",
                      "created_at": "2026-08-11T19:29:03.507Z",
                      "evaluator_email": "verifier@example.com",
                      "evaluator_id": "kx7110kst49nj4qm4m1844k1qh8c89zc",
                      "id": "ks7cv767171mgyr1h7kyz68exn8c9csv",
                      "plan_id": "kn7dkvygf1n362yd6sk197f26n8c9t4v",
                      "plan_name": "Verify Plan",
                      "recusal_reason": null,
                      "recused": false,
                      "round": 3,
                      "scores": {
                        "overall": 4
                      },
                      "session_id": "k575rnyz47j4d4qnh0fh3mh5rh8c9mm8",
                      "session_title": "Verification Talk (edited)",
                      "values": {}
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/evaluators": {
      "get": {
        "operationId": "listEvaluators",
        "tags": [
          "Evaluation"
        ],
        "summary": "List evaluators",
        "description": "Everyone reviewing on this event, across every plan, with what they were assigned, what they have finished and what is still outstanding. `?plan_id=` narrows to one round.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:contacts` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.",
        "x-required-scope": "read:contacts",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          },
          {
            "$ref": "#/components/parameters/plan_id"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EvaluatorsPage"
                },
                "example": {
                  "data": [
                    {
                      "assigned_count": 8,
                      "assigned_submission_ids": [
                        "k57c8t51z27m64nqk6mwnqae5d8c9ffq",
                        "k57f9gyjryn3d1d7996rdtqm5d8c8zb5"
                      ],
                      "completed_count": 6,
                      "created_at": "2026-08-11T19:27:45.331Z",
                      "custom_assignment": false,
                      "email": "alex.rivera@example.com",
                      "id": "kx780cw1zr9eqkpvghkmf5rfdh8c87bf",
                      "last_reminded_at": null,
                      "name": "Alex Rivera",
                      "outstanding_count": 2,
                      "plan_id": "kn78gh8vhgya5k09htqyz7cct58c8k2k",
                      "plan_name": "Round 1 — Programme Committee",
                      "plan_round": 1,
                      "recused_count": 0,
                      "review_path": "/review/demo-eval-alex",
                      "token": "demo-eval-alex"
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 1,
                    "page_size": 1,
                    "totalPages": 3,
                    "totalResults": 3,
                    "total_pages": 3,
                    "total_results": 3
                  },
                  "results": [
                    {
                      "assigned_count": 8,
                      "assigned_submission_ids": [
                        "k57c8t51z27m64nqk6mwnqae5d8c9ffq",
                        "k57f9gyjryn3d1d7996rdtqm5d8c8zb5"
                      ],
                      "completed_count": 6,
                      "created_at": "2026-08-11T19:27:45.331Z",
                      "custom_assignment": false,
                      "email": "alex.rivera@example.com",
                      "id": "kx780cw1zr9eqkpvghkmf5rfdh8c87bf",
                      "last_reminded_at": null,
                      "name": "Alex Rivera",
                      "outstanding_count": 2,
                      "plan_id": "kn78gh8vhgya5k09htqyz7cct58c8k2k",
                      "plan_name": "Round 1 — Programme Committee",
                      "plan_round": 1,
                      "recused_count": 0,
                      "review_path": "/review/demo-eval-alex",
                      "token": "demo-eval-alex"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/evaluators/{evaluatorId}": {
      "put": {
        "operationId": "updateEvaluator",
        "tags": [
          "Evaluation"
        ],
        "summary": "Update an evaluator",
        "description": "Rename them, or re-cut their assigned queue.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:contacts` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `event_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:contacts",
        "x-rate-limit-bucket": "event_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/evaluatorId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EvaluatorWriteBody"
              },
              "example": {
                "assigned_submission_ids": [
                  "k17abc…",
                  "k17def…"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EvaluatorEnvelope"
                },
                "example": {
                  "data": {
                    "assigned_count": 8,
                    "assigned_submission_ids": [
                      "k570fhnr7rfajzm9chz9pzpw3s8c90bg",
                      "k5748as8c8s7f6n4wcka9rtvsd8c94dp"
                    ],
                    "completed_count": 6,
                    "created_at": "2026-08-11T13:10:05.999Z",
                    "custom_assignment": false,
                    "email": "alex.rivera@example.com",
                    "id": "kx7ejh0w39ebhdv3mvhqzpsrkx8c8k32",
                    "last_reminded_at": null,
                    "name": "Alex Rivera",
                    "outstanding_count": 2,
                    "plan_id": "kn74xm0r2pddem9a64nmjpb8ex8c84tk",
                    "plan_name": "Round 1 — Programme Committee",
                    "plan_round": 1,
                    "recused_count": 0,
                    "review_path": "/review/demo-eval-alex",
                    "token": "demo-eval-alex"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "delete": {
        "operationId": "deleteEvaluator",
        "tags": [
          "Evaluation"
        ],
        "summary": "Remove an evaluator",
        "description": "Removes the reviewer and the scores they submitted, so no orphaned rows sit in the averages. Their review link stops working immediately.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:contacts` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `event_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:contacts",
        "x-rate-limit-bucket": "event_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/evaluatorId"
          }
        ],
        "responses": {
          "204": {
            "description": "No content.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/evaluators/create": {
      "post": {
        "operationId": "createEvaluator",
        "tags": [
          "Evaluation"
        ],
        "summary": "Add an evaluator",
        "description": "Adds a reviewer to a plan and mints their magic review link (`review_path`). Idempotent on email within the plan. Pass `assigned_submission_ids` to hand-pick their queue; omit it and they review the whole pool.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:contacts` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `event_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:contacts",
        "x-rate-limit-bucket": "event_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EvaluatorWriteBody"
              },
              "example": {
                "plan_id": "k37abc…",
                "email": "reviewer@example.com",
                "name": "Alan Turing",
                "assigned_submission_ids": [
                  "k17abc…"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EvaluatorEnvelope"
                },
                "example": {
                  "data": {
                    "assigned_count": 8,
                    "assigned_submission_ids": [
                      "k570fhnr7rfajzm9chz9pzpw3s8c90bg",
                      "k5748as8c8s7f6n4wcka9rtvsd8c94dp"
                    ],
                    "completed_count": 6,
                    "created_at": "2026-08-11T13:10:05.999Z",
                    "custom_assignment": false,
                    "email": "alex.rivera@example.com",
                    "id": "kx7ejh0w39ebhdv3mvhqzpsrkx8c8k32",
                    "last_reminded_at": null,
                    "name": "Alex Rivera",
                    "outstanding_count": 2,
                    "plan_id": "kn74xm0r2pddem9a64nmjpb8ex8c84tk",
                    "plan_name": "Round 1 — Programme Committee",
                    "plan_round": 1,
                    "recused_count": 0,
                    "review_path": "/review/demo-eval-alex",
                    "token": "demo-eval-alex"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/fields": {
      "get": {
        "operationId": "listFields",
        "tags": [
          "Event Settings"
        ],
        "summary": "List fields",
        "description": "Every field definition on the event — the CFP form's questions plus its participant fields. These are the `internal_name`s you write through `PUT /sessions/{id}/fields`.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          },
          {
            "$ref": "#/components/parameters/search"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FieldsPage"
                },
                "example": {
                  "data": [
                    {
                      "contains_pii": false,
                      "createdAt": "2026-08-11T19:27:45.331Z",
                      "enabled": true,
                      "field_source": "standard",
                      "field_type": "short_text",
                      "form_id": "jd7bzfgdxhb9ghkbs2kxw57g8n8c985k",
                      "form_slug": "cfp",
                      "help": "Aim for something an attendee could choose from a schedule without extra context.",
                      "id": "title",
                      "internal_name": "title",
                      "options": null,
                      "public_name": "Session title",
                      "required": true,
                      "scope": "session",
                      "updatedAt": "2026-08-11T19:27:45.331Z"
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 3,
                    "page_size": 3,
                    "totalPages": 6,
                    "totalResults": 16,
                    "total_pages": 6,
                    "total_results": 16
                  },
                  "results": [
                    {
                      "contains_pii": false,
                      "createdAt": "2026-08-11T19:27:45.331Z",
                      "enabled": true,
                      "field_source": "standard",
                      "field_type": "short_text",
                      "form_id": "jd7bzfgdxhb9ghkbs2kxw57g8n8c985k",
                      "form_slug": "cfp",
                      "help": "Aim for something an attendee could choose from a schedule without extra context.",
                      "id": "title",
                      "internal_name": "title",
                      "options": null,
                      "public_name": "Session title",
                      "required": true,
                      "scope": "session",
                      "updatedAt": "2026-08-11T19:27:45.331Z"
                    }
                  ],
                  "unknownResource": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "post": {
        "operationId": "searchFields",
        "tags": [
          "Event Settings"
        ],
        "summary": "Search fields",
        "description": "Same data as the list form, with the search body Sessionboard clients send.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataSearchBody"
              },
              "example": {
                "filters": {
                  "search": "takeaways"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FieldsPage"
                },
                "example": {
                  "data": [
                    {
                      "contains_pii": false,
                      "createdAt": "2026-08-11T13:14:41.555Z",
                      "enabled": true,
                      "field_source": "standard",
                      "field_type": "short_text",
                      "form_id": "jd7567qn46wc9fcf8ba93kwcq58c9zra",
                      "form_slug": "cfp",
                      "help": "Aim for something an attendee could choose from a schedule without extra context.",
                      "id": "title",
                      "internal_name": "title",
                      "options": null,
                      "public_name": "Session title",
                      "required": true,
                      "scope": "session",
                      "updatedAt": "2026-08-11T13:14:41.555Z"
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 3,
                    "page_size": 3,
                    "totalPages": 6,
                    "totalResults": 16,
                    "total_pages": 6,
                    "total_results": 16
                  },
                  "results": [
                    {
                      "contains_pii": false,
                      "createdAt": "2026-08-11T13:14:41.555Z",
                      "enabled": true,
                      "field_source": "standard",
                      "field_type": "short_text",
                      "form_id": "jd7567qn46wc9fcf8ba93kwcq58c9zra",
                      "form_slug": "cfp",
                      "help": "Aim for something an attendee could choose from a schedule without extra context.",
                      "id": "title",
                      "internal_name": "title",
                      "options": null,
                      "public_name": "Session title",
                      "required": true,
                      "scope": "session",
                      "updatedAt": "2026-08-11T13:14:41.555Z"
                    }
                  ],
                  "unknownResource": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/fields/{fieldId}": {
      "put": {
        "operationId": "updateField",
        "tags": [
          "Field Writes"
        ],
        "summary": "Update a custom field",
        "description": "Renames a field or changes its type, options, help text or required flag. System fields (Title, Description) refuse the edit with a 400.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:fields` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `field_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:fields",
        "x-rate-limit-bucket": "field_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/fieldId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FieldWriteBody"
              },
              "example": {
                "name": "Key takeaways",
                "required": false
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FieldEnvelope"
                },
                "example": {
                  "data": {
                    "contains_pii": false,
                    "createdAt": "2026-08-11T13:14:41.555Z",
                    "enabled": true,
                    "field_source": "standard",
                    "field_type": "short_text",
                    "form_id": "jd7567qn46wc9fcf8ba93kwcq58c9zra",
                    "form_slug": "cfp",
                    "help": "Aim for something an attendee could choose from a schedule without extra context.",
                    "id": "title",
                    "internal_name": "title",
                    "options": null,
                    "public_name": "Session title",
                    "required": true,
                    "scope": "session",
                    "updatedAt": "2026-08-11T13:14:41.555Z"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "delete": {
        "operationId": "deleteField",
        "tags": [
          "Field Writes"
        ],
        "summary": "Delete a custom field",
        "description": "Removes the question from every form on the event. Answers already collected are preserved on their sessions and keep coming back in `custom_fields`.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:fields` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `field_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:fields",
        "x-rate-limit-bucket": "field_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/fieldId"
          }
        ],
        "responses": {
          "204": {
            "description": "No content.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/fields/create": {
      "post": {
        "operationId": "createField",
        "tags": [
          "Field Writes"
        ],
        "summary": "Create a custom field",
        "description": "Appends a question to the event's CFP form. Custom fields and form questions are the same thing here, so a field created through the API shows up in the form builder and on the public submission form.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:fields` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `field_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:fields",
        "x-rate-limit-bucket": "field_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FieldWriteBody"
              },
              "example": {
                "name": "Key takeaways",
                "type": "long_text",
                "required": true,
                "help": "Three bullets an attendee should leave with."
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FieldEnvelope"
                },
                "example": {
                  "data": {
                    "contains_pii": false,
                    "createdAt": "2026-08-11T13:14:41.555Z",
                    "enabled": true,
                    "field_source": "standard",
                    "field_type": "short_text",
                    "form_id": "jd7567qn46wc9fcf8ba93kwcq58c9zra",
                    "form_slug": "cfp",
                    "help": "Aim for something an attendee could choose from a schedule without extra context.",
                    "id": "title",
                    "internal_name": "title",
                    "options": null,
                    "public_name": "Session title",
                    "required": true,
                    "scope": "session",
                    "updatedAt": "2026-08-11T13:14:41.555Z"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/formats": {
      "get": {
        "operationId": "listFormats",
        "tags": [
          "Event Settings"
        ],
        "summary": "List formats",
        "description": "Every format configured on the event.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          },
          {
            "$ref": "#/components/parameters/search"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataPage"
                },
                "example": {
                  "data": [
                    {
                      "created_at": null,
                      "id": "Keynote",
                      "name": "Keynote",
                      "order": 0,
                      "updated_at": null
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 25,
                    "page_size": 25,
                    "totalPages": 1,
                    "totalResults": 5,
                    "total_pages": 1,
                    "total_results": 5
                  },
                  "results": [
                    {
                      "created_at": null,
                      "id": "Keynote",
                      "name": "Keynote",
                      "order": 0,
                      "updated_at": null
                    }
                  ],
                  "unknownResource": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "post": {
        "operationId": "searchFormats",
        "tags": [
          "Event Settings"
        ],
        "summary": "Search formats",
        "description": "Same data as the list form, with the search body Sessionboard clients send.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataSearchBody"
              },
              "example": {
                "filters": {
                  "search": "talk"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataPage"
                },
                "example": {
                  "data": [
                    {
                      "created_at": null,
                      "id": "Keynote",
                      "name": "Keynote",
                      "order": 0,
                      "updated_at": null
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 25,
                    "page_size": 25,
                    "totalPages": 1,
                    "totalResults": 5,
                    "total_pages": 1,
                    "total_results": 5
                  },
                  "results": [
                    {
                      "created_at": null,
                      "id": "Keynote",
                      "name": "Keynote",
                      "order": 0,
                      "updated_at": null
                    }
                  ],
                  "unknownResource": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/formats/{id}": {
      "put": {
        "operationId": "updateFormat",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Update a format",
        "description": "Renames or reorders a format. Formats have no table of their own: they are the options on the CFP form's `format` question, so this edits that question and the form builder shows the change immediately.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataWriteBody"
              },
              "example": {
                "name": "Lightning talk (10 min)"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataEnvelope"
                },
                "example": {
                  "data": {
                    "created_at": null,
                    "id": "Keynote",
                    "name": "Keynote",
                    "order": 0,
                    "updated_at": null
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "delete": {
        "operationId": "deleteFormat",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Delete a format",
        "description": "Removes the format. Formats have no table of their own: they are the options on the CFP form's `format` question, so this edits that question and the form builder shows the change immediately.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "responses": {
          "204": {
            "description": "No content.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/formats/create": {
      "post": {
        "operationId": "createFormat",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Create a format",
        "description": "Adds a format to the event. Formats have no table of their own: they are the options on the CFP form's `format` question, so this edits that question and the form builder shows the change immediately.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataWriteBody"
              },
              "example": {
                "name": "Lightning Talk"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataEnvelope"
                },
                "example": {
                  "data": {
                    "created_at": null,
                    "id": "Keynote",
                    "name": "Keynote",
                    "order": 0,
                    "updated_at": null
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/forms": {
      "get": {
        "operationId": "listForms",
        "tags": [
          "Forms"
        ],
        "summary": "List CFP forms",
        "description": "Every submission form on the event, with its public URL, its questions, its participant rules and its live submission and draft counts.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.",
        "x-required-scope": "read:events",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          },
          {
            "$ref": "#/components/parameters/search"
          },
          {
            "$ref": "#/components/parameters/status"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormsPage"
                },
                "example": {
                  "data": [
                    {
                      "close_at": "2026-09-16T06:59:00.000Z",
                      "created_at": "2026-08-11T19:27:45.331Z",
                      "draft_count": 3,
                      "external_title": "Call for Speakers",
                      "id": "jd7bzfgdxhb9ghkbs2kxw57g8n8c985k",
                      "internal_name": "CFP 2026 — main call",
                      "is_open": true,
                      "kind": "abstract",
                      "notify_emails": [
                        "organizer@demo.sessionboard.dev"
                      ],
                      "page_heading": "Submit a talk",
                      "participant_config": {
                        "chairperson_enabled": false,
                        "fields": [
                          {
                            "enabled": true,
                            "help": null,
                            "id": "firstName",
                            "internal_name": "participant.firstName",
                            "label": "First name",
                            "locked": true,
                            "required": true
                          },
                          {
                            "enabled": true,
                            "help": null,
                            "id": "lastName",
                            "internal_name": "participant.lastName",
                            "label": "Last name",
                            "locked": true,
                            "required": true
                          }
                        ],
                        "moderator_enabled": false,
                        "send_confirmation_email": true,
                        "speaker_max": 3,
                        "speaker_min": 1
                      },
                      "public_url": "/submit/ai-engineer/ai-summit-2026/cfp",
                      "questions": [
                        {
                          "enabled": true,
                          "field_type": "short_text",
                          "help": "Aim for something an attendee could choose from a schedule without extra context.",
                          "id": "title",
                          "internal_name": "title",
                          "is_track_question": false,
                          "label": "Session title",
                          "locked": true,
                          "max_chars": 120,
                          "options": null,
                          "order": 0,
                          "placeholder": "A clear, specific title",
                          "public_name": "Session title",
                          "required": true,
                          "show_if": null,
                          "type": "short_text"
                        },
                        {
                          "enabled": true,
                          "field_type": "long_text",
                          "help": "150–300 words works best. This is what reviewers read first.",
                          "id": "description",
                          "internal_name": "description",
                          "is_track_question": false,
                          "label": "Session description",
                          "locked": true,
                          "max_chars": 2000,
                          "options": null,
                          "order": 1,
                          "placeholder": "What will you cover, and what will people leave knowing?",
                          "public_name": "Session description",
                          "required": true,
                          "show_if": null,
                          "type": "long_text"
                        }
                      ],
                      "settings": {
                        "allow_drafts": true,
                        "auto_redirect_to_portal": false,
                        "limit_per_user": 3,
                        "send_reminder_email": true,
                        "success_message": "Thanks — your proposal is in. We'll email you when the programme committee has reviewed it."
                      },
                      "show_welcome_message": true,
                      "slug": "cfp",
                      "status": "open",
                      "submission_count": 15,
                      "updated_at": "2026-08-11T19:27:45.331Z",
                      "welcome_message": "We're looking for practitioner talks: things you built, things that broke, and what you learned. You don't need to be a famous speaker — you need a real story and something the audience can use.\n\nThe call closes on 15 September 2026. You may submit up to three proposals, and you can save a draft and come back to it at any time."
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 1,
                    "page_size": 1,
                    "totalPages": 1,
                    "totalResults": 1,
                    "total_pages": 1,
                    "total_results": 1
                  },
                  "results": [
                    {
                      "close_at": "2026-09-16T06:59:00.000Z",
                      "created_at": "2026-08-11T19:27:45.331Z",
                      "draft_count": 3,
                      "external_title": "Call for Speakers",
                      "id": "jd7bzfgdxhb9ghkbs2kxw57g8n8c985k",
                      "internal_name": "CFP 2026 — main call",
                      "is_open": true,
                      "kind": "abstract",
                      "notify_emails": [
                        "organizer@demo.sessionboard.dev"
                      ],
                      "page_heading": "Submit a talk",
                      "participant_config": {
                        "chairperson_enabled": false,
                        "fields": [
                          {
                            "enabled": true,
                            "help": null,
                            "id": "firstName",
                            "internal_name": "participant.firstName",
                            "label": "First name",
                            "locked": true,
                            "required": true
                          },
                          {
                            "enabled": true,
                            "help": null,
                            "id": "lastName",
                            "internal_name": "participant.lastName",
                            "label": "Last name",
                            "locked": true,
                            "required": true
                          }
                        ],
                        "moderator_enabled": false,
                        "send_confirmation_email": true,
                        "speaker_max": 3,
                        "speaker_min": 1
                      },
                      "public_url": "/submit/ai-engineer/ai-summit-2026/cfp",
                      "questions": [
                        {
                          "enabled": true,
                          "field_type": "short_text",
                          "help": "Aim for something an attendee could choose from a schedule without extra context.",
                          "id": "title",
                          "internal_name": "title",
                          "is_track_question": false,
                          "label": "Session title",
                          "locked": true,
                          "max_chars": 120,
                          "options": null,
                          "order": 0,
                          "placeholder": "A clear, specific title",
                          "public_name": "Session title",
                          "required": true,
                          "show_if": null,
                          "type": "short_text"
                        },
                        {
                          "enabled": true,
                          "field_type": "long_text",
                          "help": "150–300 words works best. This is what reviewers read first.",
                          "id": "description",
                          "internal_name": "description",
                          "is_track_question": false,
                          "label": "Session description",
                          "locked": true,
                          "max_chars": 2000,
                          "options": null,
                          "order": 1,
                          "placeholder": "What will you cover, and what will people leave knowing?",
                          "public_name": "Session description",
                          "required": true,
                          "show_if": null,
                          "type": "long_text"
                        }
                      ],
                      "settings": {
                        "allow_drafts": true,
                        "auto_redirect_to_portal": false,
                        "limit_per_user": 3,
                        "send_reminder_email": true,
                        "success_message": "Thanks — your proposal is in. We'll email you when the programme committee has reviewed it."
                      },
                      "show_welcome_message": true,
                      "slug": "cfp",
                      "status": "open",
                      "submission_count": 15,
                      "updated_at": "2026-08-11T19:27:45.331Z",
                      "welcome_message": "We're looking for practitioner talks: things you built, things that broke, and what you learned. You don't need to be a famous speaker — you need a real story and something the audience can use.\n\nThe call closes on 15 September 2026. You may submit up to three proposals, and you can save a draft and come back to it at any time."
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/forms/{formId}": {
      "get": {
        "operationId": "getForm",
        "tags": [
          "Forms"
        ],
        "summary": "Get a form",
        "description": "One form in full — addressable by id or by its public slug. `questions[]` are the same objects `GET /fields` returns, in the order the public form renders them.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/formId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormEnvelope"
                },
                "example": {
                  "data": {
                    "close_at": "2026-09-16T06:59:00.000Z",
                    "created_at": "2026-08-11T19:27:45.331Z",
                    "draft_count": 3,
                    "external_title": "Call for Speakers",
                    "id": "jd7bzfgdxhb9ghkbs2kxw57g8n8c985k",
                    "internal_name": "CFP 2026 — main call",
                    "is_open": true,
                    "kind": "abstract",
                    "notify_emails": [
                      "organizer@demo.sessionboard.dev"
                    ],
                    "page_heading": "Submit a talk",
                    "participant_config": {
                      "chairperson_enabled": false,
                      "fields": [
                        {
                          "enabled": true,
                          "help": null,
                          "id": "firstName",
                          "internal_name": "participant.firstName",
                          "label": "First name",
                          "locked": true,
                          "required": true
                        },
                        {
                          "enabled": true,
                          "help": null,
                          "id": "lastName",
                          "internal_name": "participant.lastName",
                          "label": "Last name",
                          "locked": true,
                          "required": true
                        }
                      ],
                      "moderator_enabled": false,
                      "send_confirmation_email": true,
                      "speaker_max": 3,
                      "speaker_min": 1
                    },
                    "public_url": "/submit/ai-engineer/ai-summit-2026/cfp",
                    "questions": [
                      {
                        "enabled": true,
                        "field_type": "short_text",
                        "help": "Aim for something an attendee could choose from a schedule without extra context.",
                        "id": "title",
                        "internal_name": "title",
                        "is_track_question": false,
                        "label": "Session title",
                        "locked": true,
                        "max_chars": 120,
                        "options": null,
                        "order": 0,
                        "placeholder": "A clear, specific title",
                        "public_name": "Session title",
                        "required": true,
                        "show_if": null,
                        "type": "short_text"
                      },
                      {
                        "enabled": true,
                        "field_type": "long_text",
                        "help": "150–300 words works best. This is what reviewers read first.",
                        "id": "description",
                        "internal_name": "description",
                        "is_track_question": false,
                        "label": "Session description",
                        "locked": true,
                        "max_chars": 2000,
                        "options": null,
                        "order": 1,
                        "placeholder": "What will you cover, and what will people leave knowing?",
                        "public_name": "Session description",
                        "required": true,
                        "show_if": null,
                        "type": "long_text"
                      }
                    ],
                    "settings": {
                      "allow_drafts": true,
                      "auto_redirect_to_portal": false,
                      "limit_per_user": 3,
                      "send_reminder_email": true,
                      "success_message": "Thanks — your proposal is in. We'll email you when the programme committee has reviewed it."
                    },
                    "show_welcome_message": true,
                    "slug": "cfp",
                    "status": "open",
                    "submission_count": 15,
                    "updated_at": "2026-08-11T19:27:45.331Z",
                    "welcome_message": "We're looking for practitioner talks: things you built, things that broke, and what you learned. You don't need to be a famous speaker — you need a real story and something the audience can use.\n\nThe call closes on 15 September 2026. You may submit up to three proposals, and you can save a draft and come back to it at any time."
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "put": {
        "operationId": "updateForm",
        "tags": [
          "Forms"
        ],
        "summary": "Update a form",
        "description": "Partial update, including replacing `questions` wholesale. The locked system questions (Title, Description) must stay on the form — dropping one answers 400 rather than breaking the public page silently. Set `status: \"closed\"` to close the CFP.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:fields` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `field_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:fields",
        "x-rate-limit-bucket": "field_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/formId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FormWriteBody"
              },
              "example": {
                "status": "closed",
                "close_at": "2026-08-31T23:59:00.000Z",
                "settings": {
                  "allow_drafts": true,
                  "send_reminder_email": true
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormEnvelope"
                },
                "example": {
                  "data": {
                    "close_at": "2026-09-16T06:59:00.000Z",
                    "created_at": "2026-08-11T13:10:05.999Z",
                    "draft_count": 3,
                    "external_title": "Call for Speakers",
                    "id": "jd7cwqg5690sj0ytnx0syjr7tx8c9hwj",
                    "internal_name": "CFP 2026 — main call",
                    "is_open": true,
                    "kind": "abstract",
                    "notify_emails": [
                      "organizer@demo.sessionboard.dev"
                    ],
                    "page_heading": "Submit a talk",
                    "participant_config": {
                      "chairperson_enabled": false,
                      "fields": [
                        {
                          "enabled": true,
                          "help": null,
                          "id": "firstName",
                          "internal_name": "participant.firstName",
                          "label": "First name",
                          "locked": true,
                          "required": true
                        },
                        {
                          "enabled": true,
                          "help": null,
                          "id": "lastName",
                          "internal_name": "participant.lastName",
                          "label": "Last name",
                          "locked": true,
                          "required": true
                        }
                      ],
                      "moderator_enabled": false,
                      "send_confirmation_email": true,
                      "speaker_max": 3,
                      "speaker_min": 1
                    },
                    "public_url": "/submit/ai-summit-2026/cfp",
                    "questions": [
                      {
                        "enabled": true,
                        "field_type": "short_text",
                        "help": "Aim for something an attendee could choose from a schedule without extra context.",
                        "id": "title",
                        "internal_name": "title",
                        "is_track_question": false,
                        "label": "Session title",
                        "locked": true,
                        "max_chars": 120,
                        "options": null,
                        "order": 0,
                        "placeholder": "A clear, specific title",
                        "public_name": "Session title",
                        "required": true,
                        "show_if": null,
                        "type": "short_text"
                      },
                      {
                        "enabled": true,
                        "field_type": "long_text",
                        "help": "150–300 words works best. This is what reviewers read first.",
                        "id": "description",
                        "internal_name": "description",
                        "is_track_question": false,
                        "label": "Session description",
                        "locked": true,
                        "max_chars": 2000,
                        "options": null,
                        "order": 1,
                        "placeholder": "What will you cover, and what will people leave knowing?",
                        "public_name": "Session description",
                        "required": true,
                        "show_if": null,
                        "type": "long_text"
                      }
                    ],
                    "settings": {
                      "allow_drafts": true,
                      "auto_redirect_to_portal": true,
                      "limit_per_user": 3,
                      "send_reminder_email": true,
                      "success_message": "Thanks — your proposal is in. We'll email you when the programme committee has reviewed it."
                    },
                    "show_welcome_message": true,
                    "slug": "cfp",
                    "status": "open",
                    "submission_count": 13,
                    "updated_at": "2026-08-11T13:10:05.999Z",
                    "welcome_message": "We're looking for practitioner talks: things you built, things that broke, and what you learned. You don't need to be a famous speaker — you need a real story and something the audience can use.\n\nThe call closes on 15 September 2026. You may submit up to three proposals, and you can save a draft and come back to it at any time."
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "delete": {
        "operationId": "deleteForm",
        "tags": [
          "Forms"
        ],
        "summary": "Delete a form",
        "description": "Refused with a 400 once the form has submissions — close it instead, which keeps every submission readable. Requires the admin role.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:fields` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `field_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:fields",
        "x-rate-limit-bucket": "field_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/formId"
          }
        ],
        "responses": {
          "204": {
            "description": "No content.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/forms/create": {
      "post": {
        "operationId": "createForm",
        "tags": [
          "Forms"
        ],
        "summary": "Create a form",
        "description": "Creates a call-for-speakers form. Omit `questions` and it starts from the same default question set the form builder uses, with the Track question pre-filled from the event's tracks. The form is live at its `public_url` immediately.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:fields` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `field_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:fields",
        "x-rate-limit-bucket": "field_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/FormWriteBody"
              },
              "example": {
                "internal_name": "Main CFP 2026",
                "external_title": "Call for Speakers — AI Summit 2026",
                "kind": "abstract",
                "slug": "cfp",
                "page_heading": "Speak at AI Summit 2026",
                "notify_emails": [
                  "program@aisummit.example.com"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FormEnvelope"
                },
                "example": {
                  "data": {
                    "close_at": "2026-09-16T06:59:00.000Z",
                    "created_at": "2026-08-11T13:10:05.999Z",
                    "draft_count": 3,
                    "external_title": "Call for Speakers",
                    "id": "jd7cwqg5690sj0ytnx0syjr7tx8c9hwj",
                    "internal_name": "CFP 2026 — main call",
                    "is_open": true,
                    "kind": "abstract",
                    "notify_emails": [
                      "organizer@demo.sessionboard.dev"
                    ],
                    "page_heading": "Submit a talk",
                    "participant_config": {
                      "chairperson_enabled": false,
                      "fields": [
                        {
                          "enabled": true,
                          "help": null,
                          "id": "firstName",
                          "internal_name": "participant.firstName",
                          "label": "First name",
                          "locked": true,
                          "required": true
                        },
                        {
                          "enabled": true,
                          "help": null,
                          "id": "lastName",
                          "internal_name": "participant.lastName",
                          "label": "Last name",
                          "locked": true,
                          "required": true
                        }
                      ],
                      "moderator_enabled": false,
                      "send_confirmation_email": true,
                      "speaker_max": 3,
                      "speaker_min": 1
                    },
                    "public_url": "/submit/ai-summit-2026/cfp",
                    "questions": [
                      {
                        "enabled": true,
                        "field_type": "short_text",
                        "help": "Aim for something an attendee could choose from a schedule without extra context.",
                        "id": "title",
                        "internal_name": "title",
                        "is_track_question": false,
                        "label": "Session title",
                        "locked": true,
                        "max_chars": 120,
                        "options": null,
                        "order": 0,
                        "placeholder": "A clear, specific title",
                        "public_name": "Session title",
                        "required": true,
                        "show_if": null,
                        "type": "short_text"
                      },
                      {
                        "enabled": true,
                        "field_type": "long_text",
                        "help": "150–300 words works best. This is what reviewers read first.",
                        "id": "description",
                        "internal_name": "description",
                        "is_track_question": false,
                        "label": "Session description",
                        "locked": true,
                        "max_chars": 2000,
                        "options": null,
                        "order": 1,
                        "placeholder": "What will you cover, and what will people leave knowing?",
                        "public_name": "Session description",
                        "required": true,
                        "show_if": null,
                        "type": "long_text"
                      }
                    ],
                    "settings": {
                      "allow_drafts": true,
                      "auto_redirect_to_portal": true,
                      "limit_per_user": 3,
                      "send_reminder_email": true,
                      "success_message": "Thanks — your proposal is in. We'll email you when the programme committee has reviewed it."
                    },
                    "show_welcome_message": true,
                    "slug": "cfp",
                    "status": "open",
                    "submission_count": 13,
                    "updated_at": "2026-08-11T13:10:05.999Z",
                    "welcome_message": "We're looking for practitioner talks: things you built, things that broke, and what you learned. You don't need to be a famous speaker — you need a real story and something the audience can use.\n\nThe call closes on 15 September 2026. You may submit up to three proposals, and you can save a draft and come back to it at any time."
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/languages": {
      "get": {
        "operationId": "listLanguages",
        "tags": [
          "Event Settings"
        ],
        "summary": "List languages",
        "description": "Every language configured on the event.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          },
          {
            "$ref": "#/components/parameters/search"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataPage"
                },
                "example": {
                  "data": [
                    {
                      "created_at": null,
                      "id": "English",
                      "name": "English",
                      "order": 0,
                      "updated_at": null
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 25,
                    "page_size": 25,
                    "totalPages": 1,
                    "totalResults": 3,
                    "total_pages": 1,
                    "total_results": 3
                  },
                  "results": [
                    {
                      "created_at": null,
                      "id": "English",
                      "name": "English",
                      "order": 0,
                      "updated_at": null
                    }
                  ],
                  "unknownResource": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "post": {
        "operationId": "searchLanguages",
        "tags": [
          "Event Settings"
        ],
        "summary": "Search languages",
        "description": "Same data as the list form, with the search body Sessionboard clients send.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataSearchBody"
              },
              "example": {
                "filters": {
                  "search": "eng"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataPage"
                },
                "example": {
                  "data": [
                    {
                      "created_at": null,
                      "id": "English",
                      "name": "English",
                      "order": 0,
                      "updated_at": null
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 25,
                    "page_size": 25,
                    "totalPages": 1,
                    "totalResults": 3,
                    "total_pages": 1,
                    "total_results": 3
                  },
                  "results": [
                    {
                      "created_at": null,
                      "id": "English",
                      "name": "English",
                      "order": 0,
                      "updated_at": null
                    }
                  ],
                  "unknownResource": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/languages/{id}": {
      "put": {
        "operationId": "updateLanguage",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Update a language",
        "description": "Renames or reorders a language. Languages have no table of their own: they are the options on the CFP form's `language` question, so this edits that question and the form builder shows the change immediately.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataWriteBody"
              },
              "example": {
                "name": "Español"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataEnvelope"
                },
                "example": {
                  "data": {
                    "created_at": null,
                    "id": "English",
                    "name": "English",
                    "order": 0,
                    "updated_at": null
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "delete": {
        "operationId": "deleteLanguage",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Delete a language",
        "description": "Removes the language. Languages have no table of their own: they are the options on the CFP form's `language` question, so this edits that question and the form builder shows the change immediately.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "responses": {
          "204": {
            "description": "No content.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/languages/create": {
      "post": {
        "operationId": "createLanguage",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Create a language",
        "description": "Adds a language to the event. Languages have no table of their own: they are the options on the CFP form's `language` question, so this edits that question and the form builder shows the change immediately.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataWriteBody"
              },
              "example": {
                "name": "Spanish"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataEnvelope"
                },
                "example": {
                  "data": {
                    "created_at": null,
                    "id": "English",
                    "name": "English",
                    "order": 0,
                    "updated_at": null
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/levels": {
      "get": {
        "operationId": "listLevels",
        "tags": [
          "Event Settings"
        ],
        "summary": "List levels",
        "description": "Every level configured on the event.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          },
          {
            "$ref": "#/components/parameters/search"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataPage"
                },
                "example": {
                  "data": [
                    {
                      "created_at": null,
                      "id": "Advanced",
                      "name": "Advanced",
                      "order": 0,
                      "updated_at": null
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 25,
                    "page_size": 25,
                    "totalPages": 1,
                    "totalResults": 4,
                    "total_pages": 1,
                    "total_results": 4
                  },
                  "results": [
                    {
                      "created_at": null,
                      "id": "Advanced",
                      "name": "Advanced",
                      "order": 0,
                      "updated_at": null
                    }
                  ],
                  "unknownResource": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "post": {
        "operationId": "searchLevels",
        "tags": [
          "Event Settings"
        ],
        "summary": "Search levels",
        "description": "Same data as the list form, with the search body Sessionboard clients send.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataSearchBody"
              },
              "example": {
                "filters": {
                  "search": "adv"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataPage"
                },
                "example": {
                  "data": [
                    {
                      "created_at": null,
                      "id": "Advanced",
                      "name": "Advanced",
                      "order": 0,
                      "updated_at": null
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 25,
                    "page_size": 25,
                    "totalPages": 1,
                    "totalResults": 3,
                    "total_pages": 1,
                    "total_results": 3
                  },
                  "results": [
                    {
                      "created_at": null,
                      "id": "Advanced",
                      "name": "Advanced",
                      "order": 0,
                      "updated_at": null
                    }
                  ],
                  "unknownResource": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/levels/{id}": {
      "put": {
        "operationId": "updateLevel",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Update a level",
        "description": "Renames or reorders a level. Levels have no table of their own: they are the options on the CFP form's `level` question, so this edits that question and the form builder shows the change immediately.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataWriteBody"
              },
              "example": {
                "name": "Advanced / deep dive"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataEnvelope"
                },
                "example": {
                  "data": {
                    "created_at": null,
                    "id": "Advanced",
                    "name": "Advanced",
                    "order": 0,
                    "updated_at": null
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "delete": {
        "operationId": "deleteLevel",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Delete a level",
        "description": "Removes the level. Levels have no table of their own: they are the options on the CFP form's `level` question, so this edits that question and the form builder shows the change immediately.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "responses": {
          "204": {
            "description": "No content.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/levels/create": {
      "post": {
        "operationId": "createLevel",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Create a level",
        "description": "Adds a level to the event. Levels have no table of their own: they are the options on the CFP form's `level` question, so this edits that question and the form builder shows the change immediately.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataWriteBody"
              },
              "example": {
                "name": "Advanced"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataEnvelope"
                },
                "example": {
                  "data": {
                    "created_at": null,
                    "id": "Advanced",
                    "name": "Advanced",
                    "order": 0,
                    "updated_at": null
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/rooms": {
      "get": {
        "operationId": "listRooms",
        "tags": [
          "Event Settings"
        ],
        "summary": "List rooms",
        "description": "Every room configured on the event.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          },
          {
            "$ref": "#/components/parameters/search"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataPage"
                },
                "example": {
                  "data": [
                    {
                      "capacity": 300,
                      "created_at": "2026-08-11T19:27:45.331Z",
                      "id": "js7bf7gcc7h75dees2qgsk7wks8c8yja",
                      "name": "Main Stage",
                      "order": 0,
                      "updated_at": "2026-08-11T19:27:45.331Z"
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 25,
                    "page_size": 25,
                    "totalPages": 1,
                    "totalResults": 2,
                    "total_pages": 1,
                    "total_results": 2
                  },
                  "results": [
                    {
                      "capacity": 300,
                      "created_at": "2026-08-11T19:27:45.331Z",
                      "id": "js7bf7gcc7h75dees2qgsk7wks8c8yja",
                      "name": "Main Stage",
                      "order": 0,
                      "updated_at": "2026-08-11T19:27:45.331Z"
                    }
                  ],
                  "unknownResource": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "post": {
        "operationId": "searchRooms",
        "tags": [
          "Event Settings"
        ],
        "summary": "Search rooms",
        "description": "Same data as the list form, with the search body Sessionboard clients send.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataSearchBody"
              },
              "example": {
                "filters": {
                  "search": "hall"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataPage"
                },
                "example": {
                  "data": [
                    {
                      "capacity": 300,
                      "created_at": "2026-08-11T13:14:41.555Z",
                      "id": "js79bh0jgt3b6rh97t5pf9qmbx8c9nj4",
                      "name": "Main Stage",
                      "order": 0,
                      "updated_at": "2026-08-11T13:14:41.555Z"
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 25,
                    "page_size": 25,
                    "totalPages": 1,
                    "totalResults": 2,
                    "total_pages": 1,
                    "total_results": 2
                  },
                  "results": [
                    {
                      "capacity": 300,
                      "created_at": "2026-08-11T13:14:41.555Z",
                      "id": "js79bh0jgt3b6rh97t5pf9qmbx8c9nj4",
                      "name": "Main Stage",
                      "order": 0,
                      "updated_at": "2026-08-11T13:14:41.555Z"
                    }
                  ],
                  "unknownResource": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/rooms/{id}": {
      "put": {
        "operationId": "updateRoom",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Update a room",
        "description": "Renames or reorders a room.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataWriteBody"
              },
              "example": {
                "capacity": 500
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataEnvelope"
                },
                "example": {
                  "data": {
                    "capacity": 300,
                    "created_at": "2026-08-11T13:14:41.555Z",
                    "id": "js79bh0jgt3b6rh97t5pf9qmbx8c9nj4",
                    "name": "Main Stage",
                    "order": 0,
                    "updated_at": "2026-08-11T13:14:41.555Z"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "delete": {
        "operationId": "deleteRoom",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Delete a room",
        "description": "Deletes the room and unschedules anything standing in it, so the agenda never points at a room that no longer exists.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "responses": {
          "204": {
            "description": "No content.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/rooms/create": {
      "post": {
        "operationId": "createRoom",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Create a room",
        "description": "Adds a room to the event.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataWriteBody"
              },
              "example": {
                "name": "Hall B",
                "capacity": 450,
                "order": 20
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataEnvelope"
                },
                "example": {
                  "data": {
                    "capacity": 300,
                    "created_at": "2026-08-11T13:14:41.555Z",
                    "id": "js79bh0jgt3b6rh97t5pf9qmbx8c9nj4",
                    "name": "Main Stage",
                    "order": 0,
                    "updated_at": "2026-08-11T13:14:41.555Z"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/schedule.ics": {
      "get": {
        "operationId": "getScheduleFeed",
        "tags": [
          "Calendar"
        ],
        "summary": "Subscribe to the event calendar",
        "description": "RFC 5545 calendar feed of the published programme. Deliberately open: calendar clients subscribe by URL and cannot send an auth header. Only accepted, scheduled sessions of a published agenda appear.\n\n**Authentication** — none required. This endpoint is deliberately open (see the description above); sending a key anyway is harmless.",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "text/calendar": {
                "schema": {
                  "type": "string"
                },
                "example": "BEGIN:VCALENDAR\r\nVERSION:2.0\r\nPRODID:-//Trackstage//Event Schedule//EN\r\nCALSCALE:GREGORIAN\r\nMETHOD:PUBLISH\r\nX-WR-CALNAME:AI Engineer Summit 2026\r\nBEGIN:VEVENT\r\nUID:k577pznhjcx1fhk73b9vme1rvd8c9a0n@ai-summit-2026.trackstage\r\nDTSTAMP:20260811T192942Z\r\nDTSTART:20261012T090000Z\r\nDTEND:20261012T094500Z\r\nSUMMARY:Cost modelling for inference-heavy products\r\n…"
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": []
      }
    },
    "/v1/event/{eventRef}/schedule.xml": {
      "get": {
        "operationId": "getScheduleXml",
        "tags": [
          "Calendar"
        ],
        "summary": "The published programme as XML",
        "description": "The same published programme as the JSON endpoints, served as plain XML for site builders and CMSs that import a feed rather than call an API. Deliberately open, like the calendar feed — it carries exactly what the public event page already shows. Pass `?track=Name` (or several, comma-separated) to narrow it to one part of the programme.\n\n**Authentication** — none required. This endpoint is deliberately open (see the description above); sending a key anyway is harmless.",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "responses": {
          "200": {
            "description": "Success."
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": []
      }
    },
    "/v1/event/{eventRef}/session-statuses": {
      "get": {
        "operationId": "listSessionStatuses",
        "tags": [
          "Event Settings"
        ],
        "summary": "List session statuses",
        "description": "Every status a session can be in: the seven built-ins every event ships with, plus any custom labels this event added. `id` is the pipeline value for a built-in and the row id for a custom status; `pipeline_status` is always the value `?status=` filters on. Pass `include_deleted=true` to see archived ones.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          },
          {
            "$ref": "#/components/parameters/search"
          },
          {
            "$ref": "#/components/parameters/include_deleted"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatusesPage"
                },
                "example": {
                  "data": [
                    {
                      "category": "accepted",
                      "color": "green",
                      "created_at": null,
                      "created_by": null,
                      "deleted_at": null,
                      "id": "accepted",
                      "name": "Accepted",
                      "order": 10,
                      "pipeline_status": "accepted",
                      "status_id": "p57fb2kbg09t1khn58fdtjyqc18c9pnm",
                      "system": true,
                      "system_key": "accepted",
                      "updated_at": null,
                      "value": "accepted"
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 25,
                    "page_size": 25,
                    "totalPages": 1,
                    "totalResults": 8,
                    "total_pages": 1,
                    "total_results": 8
                  },
                  "results": [
                    {
                      "category": "accepted",
                      "color": "green",
                      "created_at": null,
                      "created_by": null,
                      "deleted_at": null,
                      "id": "accepted",
                      "name": "Accepted",
                      "order": 10,
                      "pipeline_status": "accepted",
                      "status_id": "p57fb2kbg09t1khn58fdtjyqc18c9pnm",
                      "system": true,
                      "system_key": "accepted",
                      "updated_at": null,
                      "value": "accepted"
                    }
                  ],
                  "unknownResource": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "post": {
        "operationId": "searchSessionStatuses",
        "tags": [
          "Event Settings"
        ],
        "summary": "Search session statuses",
        "description": "Same data as the list form, with the search body Sessionboard clients send.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataSearchBody"
              },
              "example": {
                "filters": {
                  "search": "accept"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatusesPage"
                },
                "example": {
                  "data": [
                    {
                      "category": "accepted",
                      "color": "green",
                      "created_at": null,
                      "created_by": null,
                      "deleted_at": null,
                      "id": "accepted",
                      "name": "Accepted",
                      "order": 10,
                      "pipeline_status": "accepted",
                      "status_id": "p573r4hrnkaa658391v76a7q358c8fcq",
                      "system": true,
                      "system_key": "accepted",
                      "updated_at": null,
                      "value": "accepted"
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 25,
                    "page_size": 25,
                    "totalPages": 1,
                    "totalResults": 8,
                    "total_pages": 1,
                    "total_results": 8
                  },
                  "results": [
                    {
                      "category": "accepted",
                      "color": "green",
                      "created_at": null,
                      "created_by": null,
                      "deleted_at": null,
                      "id": "accepted",
                      "name": "Accepted",
                      "order": 10,
                      "pipeline_status": "accepted",
                      "status_id": "p573r4hrnkaa658391v76a7q358c8fcq",
                      "system": true,
                      "system_key": "accepted",
                      "updated_at": null,
                      "value": "accepted"
                    }
                  ],
                  "unknownResource": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/sessions": {
      "get": {
        "operationId": "listSessions",
        "tags": [
          "Sessions"
        ],
        "summary": "List sessions",
        "description": "Paginated sessions. With no filters this returns the accepted programme — the behaviour this endpoint has always had — so existing consumers are unaffected. Passing any filter (`status`, `is_abstract`, `track_id`, `tag_id`, `search`) opts into the full pipeline, soft-deleted rows excluded.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.",
        "x-required-scope": "read:sessions",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          },
          {
            "$ref": "#/components/parameters/status"
          },
          {
            "$ref": "#/components/parameters/is_abstract"
          },
          {
            "$ref": "#/components/parameters/track_id"
          },
          {
            "$ref": "#/components/parameters/tag_id"
          },
          {
            "$ref": "#/components/parameters/search"
          },
          {
            "$ref": "#/components/parameters/expand"
          },
          {
            "$ref": "#/components/parameters/include_deleted"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionsPage"
                },
                "example": {
                  "data": [
                    {
                      "answers": {
                        "description": "<p>A talk created by the verify script.</p>",
                        "format": "Talk",
                        "language": "English",
                        "level": "Introductory",
                        "title": "Verification Talk",
                        "track": "AI Engineering"
                      },
                      "capacity": 300,
                      "chairpersons": [],
                      "created_at": "2026-08-11T19:27:52.774Z",
                      "custom_fields": [
                        {
                          "created_at": "2026-08-11T19:27:52.774Z",
                          "id": "description",
                          "internal_name": "description",
                          "name": "Session description",
                          "type": "long_text",
                          "value": "<p>A talk created by the verify script.</p>",
                          "value_raw": "<p>A talk created by the verify script.</p>"
                        },
                        {
                          "created_at": "2026-08-11T19:27:52.774Z",
                          "id": "format",
                          "internal_name": "format",
                          "name": "Format",
                          "type": "dropdown",
                          "value": "Talk",
                          "value_raw": "Talk"
                        }
                      ],
                      "decidedAt": 1786476486819,
                      "decided_at": "2026-08-11T19:28:06.819Z",
                      "deleted_at": null,
                      "description": "<p>A talk created by the verify script.</p>",
                      "durationMinutes": 45,
                      "duration_minutes": 45,
                      "endTime": 1791801900000,
                      "ends_at": "2026-10-12T10:45:00.000Z",
                      "format": {
                        "id": "Talk",
                        "name": "Talk"
                      },
                      "friendly_id": "SESS-54160",
                      "friendly_id_raw": 54160,
                      "id": "k575rnyz47j4d4qnh0fh3mh5rh8c9mm8",
                      "is_abstract": true,
                      "is_public": true,
                      "kind": "abstract",
                      "language": {
                        "id": "English",
                        "name": "English"
                      },
                      "level": {
                        "id": "Introductory",
                        "name": "Introductory"
                      },
                      "location": "Main Stage",
                      "moderators": [],
                      "notified_at": "2026-08-11T19:28:06.819Z",
                      "participants": [
                        {
                          "about": "An updated bio from the verify script.",
                          "bio": "An updated bio from the verify script.",
                          "company": null,
                          "company_name": null,
                          "created_at": "2026-08-11T19:27:51.938Z",
                          "email": "verify-e2e-msp1yrr9@example.com",
                          "firstName": "Vera",
                          "first_name": "Vera",
                          "friendly_id": "SPK-68155",
                          "friendly_id_raw": 68155,
                          "full_name": "Vera Efftest",
                          "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                          "id": "m975yb2bcxrwfxc33qzmd8pthh8c8pwg",
                          "is_public": true,
                          "jobTitle": "QA Engineer",
                          "lastName": "Efftest",
                          "last_name": "Efftest",
                          "linkedin_url": null,
                          "name": "Vera Efftest",
                          "participant_role": {
                            "core_role": "speaker",
                            "name": "Speaker",
                            "name_plural": "Speakers",
                            "slug": "speaker"
                          },
                          "phone_mobile": null,
                          "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                          "pronouns": null,
                          "salutation": null,
                          "title": "QA Engineer",
                          "twitter_url": null,
                          "updated_at": "2026-08-11T19:27:51.938Z",
                          "website_url": null,
                          "workflow_status": null
                        }
                      ],
                      "public_visible": true,
                      "room": {
                        "capacity": 300,
                        "created_at": "2026-08-11T19:27:45.331Z",
                        "id": "js7bf7gcc7h75dees2qgsk7wks8c8yja",
                        "name": "Main Stage",
                        "order": 0,
                        "updated_at": "2026-08-11T19:27:45.331Z"
                      },
                      "speakers": [
                        {
                          "about": "An updated bio from the verify script.",
                          "bio": "An updated bio from the verify script.",
                          "company": null,
                          "company_name": null,
                          "created_at": "2026-08-11T19:27:51.938Z",
                          "email": "verify-e2e-msp1yrr9@example.com",
                          "firstName": "Vera",
                          "first_name": "Vera",
                          "friendly_id": "SPK-68155",
                          "friendly_id_raw": 68155,
                          "full_name": "Vera Efftest",
                          "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                          "id": "m975yb2bcxrwfxc33qzmd8pthh8c8pwg",
                          "is_public": true,
                          "jobTitle": "QA Engineer",
                          "lastName": "Efftest",
                          "last_name": "Efftest",
                          "linkedin_url": null,
                          "name": "Vera Efftest",
                          "participant_role": {
                            "core_role": "speaker",
                            "name": "Speaker",
                            "name_plural": "Speakers",
                            "slug": "speaker"
                          },
                          "phone_mobile": null,
                          "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                          "pronouns": null,
                          "salutation": null,
                          "title": "QA Engineer",
                          "twitter_url": null,
                          "updated_at": "2026-08-11T19:27:51.938Z",
                          "website_url": null,
                          "workflow_status": null
                        }
                      ],
                      "startTime": 1791799200000,
                      "starts_at": "2026-10-12T10:00:00.000Z",
                      "status": "accepted",
                      "submittedAt": 1786476472774.8613,
                      "submitter": {
                        "about": "An updated bio from the verify script.",
                        "bio": "An updated bio from the verify script.",
                        "company": null,
                        "company_name": null,
                        "created_at": "2026-08-11T19:27:51.938Z",
                        "email": "verify-e2e-msp1yrr9@example.com",
                        "firstName": "Vera",
                        "first_name": "Vera",
                        "friendly_id": "SPK-68155",
                        "friendly_id_raw": 68155,
                        "full_name": "Vera Efftest",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                        "id": "m975yb2bcxrwfxc33qzmd8pthh8c8pwg",
                        "is_public": true,
                        "jobTitle": "QA Engineer",
                        "lastName": "Efftest",
                        "last_name": "Efftest",
                        "linkedin_url": null,
                        "name": "Vera Efftest",
                        "participant_role": null,
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                        "pronouns": null,
                        "salutation": null,
                        "title": "QA Engineer",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T19:27:51.938Z",
                        "website_url": null,
                        "workflow_status": null
                      },
                      "subsessions": [],
                      "tags": [],
                      "title": "Verification Talk (edited)",
                      "track": {
                        "color": "#2F5CE0",
                        "created_at": "2026-08-11T19:27:45.331Z",
                        "event_id": "j976eyym787qhaq02v0nea4k7x8c879q",
                        "id": "kd70s9jv39zmvkarkyrjcbk14x8c8g9d",
                        "name": "AI Engineering",
                        "order": 0,
                        "updated_at": "2026-08-11T19:27:45.331Z"
                      },
                      "trackColor": "#2F5CE0",
                      "updated_at": "2026-08-11T19:27:52.774Z"
                    }
                  ],
                  "event": {
                    "_id": "j976eyym787qhaq02v0nea4k7x8c879q",
                    "agenda_published_at": "2026-08-06T19:27:45.331Z",
                    "background_url": null,
                    "created_at": "2026-08-11T19:27:45.331Z",
                    "description": "Two days for the people building AI systems that have to work on Monday morning. Practitioner talks on evaluation, agents, retrieval, inference infrastructure and the product decisions in between — no keynote fluff, no vendor pitches.",
                    "endsAt": 1791939600000,
                    "ends_at": "2026-10-14T01:00:00.000Z",
                    "features": {
                      "custom_fields": true,
                      "translated_fields": false,
                      "webhooks": true
                    },
                    "id": "j976eyym787qhaq02v0nea4k7x8c879q",
                    "logo_url": null,
                    "name": "AI Engineer Summit 2026",
                    "organization_id": "mn7fs8btg5szyhbkqdfhtd4xmn8c8xhg",
                    "portal_settings": {
                      "allow_submission_edits": true,
                      "always_show_tasks": false,
                      "extend_task_deadlines": true
                    },
                    "public_url": "/e/ai-engineer/ai-summit-2026",
                    "slug": "ai-summit-2026",
                    "startsAt": 1791820800000,
                    "starts_at": "2026-10-12T16:00:00.000Z",
                    "timezone": "America/Los_Angeles",
                    "type": "Conference",
                    "venue": "Moscone West, San Francisco",
                    "websiteUrl": "https://example.com/ai-summit-2026",
                    "website_url": "https://example.com/ai-summit-2026"
                  },
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 1,
                    "page_size": 1,
                    "totalPages": 9,
                    "totalResults": 9,
                    "total_pages": 9,
                    "total_results": 9
                  },
                  "results": [
                    {
                      "answers": {
                        "description": "<p>A talk created by the verify script.</p>",
                        "format": "Talk",
                        "language": "English",
                        "level": "Introductory",
                        "title": "Verification Talk",
                        "track": "AI Engineering"
                      },
                      "capacity": 300,
                      "chairpersons": [],
                      "created_at": "2026-08-11T19:27:52.774Z",
                      "custom_fields": [
                        {
                          "created_at": "2026-08-11T19:27:52.774Z",
                          "id": "description",
                          "internal_name": "description",
                          "name": "Session description",
                          "type": "long_text",
                          "value": "<p>A talk created by the verify script.</p>",
                          "value_raw": "<p>A talk created by the verify script.</p>"
                        },
                        {
                          "created_at": "2026-08-11T19:27:52.774Z",
                          "id": "format",
                          "internal_name": "format",
                          "name": "Format",
                          "type": "dropdown",
                          "value": "Talk",
                          "value_raw": "Talk"
                        }
                      ],
                      "decidedAt": 1786476486819,
                      "decided_at": "2026-08-11T19:28:06.819Z",
                      "deleted_at": null,
                      "description": "<p>A talk created by the verify script.</p>",
                      "durationMinutes": 45,
                      "duration_minutes": 45,
                      "endTime": 1791801900000,
                      "ends_at": "2026-10-12T10:45:00.000Z",
                      "format": {
                        "id": "Talk",
                        "name": "Talk"
                      },
                      "friendly_id": "SESS-54160",
                      "friendly_id_raw": 54160,
                      "id": "k575rnyz47j4d4qnh0fh3mh5rh8c9mm8",
                      "is_abstract": true,
                      "is_public": true,
                      "kind": "abstract",
                      "language": {
                        "id": "English",
                        "name": "English"
                      },
                      "level": {
                        "id": "Introductory",
                        "name": "Introductory"
                      },
                      "location": "Main Stage",
                      "moderators": [],
                      "notified_at": "2026-08-11T19:28:06.819Z",
                      "participants": [
                        {
                          "about": "An updated bio from the verify script.",
                          "bio": "An updated bio from the verify script.",
                          "company": null,
                          "company_name": null,
                          "created_at": "2026-08-11T19:27:51.938Z",
                          "email": "verify-e2e-msp1yrr9@example.com",
                          "firstName": "Vera",
                          "first_name": "Vera",
                          "friendly_id": "SPK-68155",
                          "friendly_id_raw": 68155,
                          "full_name": "Vera Efftest",
                          "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                          "id": "m975yb2bcxrwfxc33qzmd8pthh8c8pwg",
                          "is_public": true,
                          "jobTitle": "QA Engineer",
                          "lastName": "Efftest",
                          "last_name": "Efftest",
                          "linkedin_url": null,
                          "name": "Vera Efftest",
                          "participant_role": {
                            "core_role": "speaker",
                            "name": "Speaker",
                            "name_plural": "Speakers",
                            "slug": "speaker"
                          },
                          "phone_mobile": null,
                          "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                          "pronouns": null,
                          "salutation": null,
                          "title": "QA Engineer",
                          "twitter_url": null,
                          "updated_at": "2026-08-11T19:27:51.938Z",
                          "website_url": null,
                          "workflow_status": null
                        }
                      ],
                      "public_visible": true,
                      "room": {
                        "capacity": 300,
                        "created_at": "2026-08-11T19:27:45.331Z",
                        "id": "js7bf7gcc7h75dees2qgsk7wks8c8yja",
                        "name": "Main Stage",
                        "order": 0,
                        "updated_at": "2026-08-11T19:27:45.331Z"
                      },
                      "speakers": [
                        {
                          "about": "An updated bio from the verify script.",
                          "bio": "An updated bio from the verify script.",
                          "company": null,
                          "company_name": null,
                          "created_at": "2026-08-11T19:27:51.938Z",
                          "email": "verify-e2e-msp1yrr9@example.com",
                          "firstName": "Vera",
                          "first_name": "Vera",
                          "friendly_id": "SPK-68155",
                          "friendly_id_raw": 68155,
                          "full_name": "Vera Efftest",
                          "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                          "id": "m975yb2bcxrwfxc33qzmd8pthh8c8pwg",
                          "is_public": true,
                          "jobTitle": "QA Engineer",
                          "lastName": "Efftest",
                          "last_name": "Efftest",
                          "linkedin_url": null,
                          "name": "Vera Efftest",
                          "participant_role": {
                            "core_role": "speaker",
                            "name": "Speaker",
                            "name_plural": "Speakers",
                            "slug": "speaker"
                          },
                          "phone_mobile": null,
                          "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                          "pronouns": null,
                          "salutation": null,
                          "title": "QA Engineer",
                          "twitter_url": null,
                          "updated_at": "2026-08-11T19:27:51.938Z",
                          "website_url": null,
                          "workflow_status": null
                        }
                      ],
                      "startTime": 1791799200000,
                      "starts_at": "2026-10-12T10:00:00.000Z",
                      "status": "accepted",
                      "submittedAt": 1786476472774.8613,
                      "submitter": {
                        "about": "An updated bio from the verify script.",
                        "bio": "An updated bio from the verify script.",
                        "company": null,
                        "company_name": null,
                        "created_at": "2026-08-11T19:27:51.938Z",
                        "email": "verify-e2e-msp1yrr9@example.com",
                        "firstName": "Vera",
                        "first_name": "Vera",
                        "friendly_id": "SPK-68155",
                        "friendly_id_raw": 68155,
                        "full_name": "Vera Efftest",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                        "id": "m975yb2bcxrwfxc33qzmd8pthh8c8pwg",
                        "is_public": true,
                        "jobTitle": "QA Engineer",
                        "lastName": "Efftest",
                        "last_name": "Efftest",
                        "linkedin_url": null,
                        "name": "Vera Efftest",
                        "participant_role": null,
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                        "pronouns": null,
                        "salutation": null,
                        "title": "QA Engineer",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T19:27:51.938Z",
                        "website_url": null,
                        "workflow_status": null
                      },
                      "subsessions": [],
                      "tags": [],
                      "title": "Verification Talk (edited)",
                      "track": {
                        "color": "#2F5CE0",
                        "created_at": "2026-08-11T19:27:45.331Z",
                        "event_id": "j976eyym787qhaq02v0nea4k7x8c879q",
                        "id": "kd70s9jv39zmvkarkyrjcbk14x8c8g9d",
                        "name": "AI Engineering",
                        "order": 0,
                        "updated_at": "2026-08-11T19:27:45.331Z"
                      },
                      "trackColor": "#2F5CE0",
                      "updated_at": "2026-08-11T19:27:52.774Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "post": {
        "operationId": "searchSessions",
        "tags": [
          "Sessions"
        ],
        "summary": "Search sessions",
        "description": "Filter, sort and page through sessions and abstracts. Results carry the full session shape including `custom_fields`, `participants` and nested track/room metadata.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.",
        "x-required-scope": "read:sessions",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SessionSearchBody"
              },
              "example": {
                "filters": {
                  "status": "accepted",
                  "isAbstract": false,
                  "search": "agents"
                },
                "sort": {
                  "order": "startsAt",
                  "sort": "asc"
                },
                "expand": [
                  "files"
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionsPage"
                },
                "example": {
                  "data": [
                    {
                      "answers": {
                        "description": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today.",
                        "format": "Panel",
                        "language": "English",
                        "level": "Intermediate",
                        "takeaways": "Honest post-mortems from four production agent systems.",
                        "title": "Closing panel: what we got wrong about agents",
                        "track": "Product"
                      },
                      "capacity": 300,
                      "chairpersons": [],
                      "created_at": "2026-08-11T13:10:05.999Z",
                      "custom_fields": [
                        {
                          "created_at": "2026-08-11T13:10:05.999Z",
                          "id": "description",
                          "internal_name": "description",
                          "name": "Session description",
                          "type": "long_text",
                          "value": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today.",
                          "value_raw": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today."
                        },
                        {
                          "created_at": "2026-08-11T13:10:05.999Z",
                          "id": "format",
                          "internal_name": "format",
                          "name": "Format",
                          "type": "dropdown",
                          "value": "Panel",
                          "value_raw": "Panel"
                        }
                      ],
                      "decidedAt": 1785935405999,
                      "decided_at": "2026-08-05T13:10:05.999Z",
                      "deleted_at": null,
                      "description": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today.",
                      "durationMinutes": 60,
                      "duration_minutes": 60,
                      "endTime": 1791936000000,
                      "ends_at": "2026-10-14T00:00:00.000Z",
                      "format": {
                        "id": "Panel",
                        "name": "Panel"
                      },
                      "friendly_id": "SESS-42342",
                      "friendly_id_raw": 42342,
                      "id": "k57b5gt5pefy4jcjg6y6023yss8c9det",
                      "is_abstract": false,
                      "is_public": true,
                      "kind": "session",
                      "language": {
                        "id": "English",
                        "name": "English"
                      },
                      "level": {
                        "id": "Intermediate",
                        "name": "Intermediate"
                      },
                      "location": "Main Stage",
                      "moderators": [],
                      "notified_at": "2026-08-06T13:10:05.999Z",
                      "participants": [
                        {
                          "about": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                          "bio": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                          "company": "Fathom Robotics",
                          "company_name": "Fathom Robotics",
                          "created_at": "2026-08-11T13:10:05.999Z",
                          "email": "noah.blackwood@example.com",
                          "firstName": "Noah",
                          "first_name": "Noah",
                          "friendly_id": "SPK-32294",
                          "friendly_id_raw": 32294,
                          "full_name": "Noah Blackwood",
                          "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                          "id": "m97ed5bzvtqddq1gm642p216js8c911f",
                          "is_public": true,
                          "jobTitle": "Chief Technology Officer",
                          "lastName": "Blackwood",
                          "last_name": "Blackwood",
                          "linkedin_url": null,
                          "name": "Noah Blackwood",
                          "participant_role": {
                            "core_role": "speaker",
                            "name": "Speaker",
                            "name_plural": "Speakers",
                            "slug": "speaker"
                          },
                          "phone_mobile": null,
                          "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                          "pronouns": null,
                          "salutation": null,
                          "title": "Chief Technology Officer",
                          "twitter_url": null,
                          "updated_at": "2026-08-11T13:10:05.999Z",
                          "website_url": null,
                          "workflow_status": null
                        },
                        {
                          "about": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                          "bio": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                          "company": "Meridian Health",
                          "company_name": "Meridian Health",
                          "created_at": "2026-08-11T13:10:05.999Z",
                          "email": "daniel.okonkwo@example.com",
                          "firstName": "Daniel",
                          "first_name": "Daniel",
                          "friendly_id": "SPK-64947",
                          "friendly_id_raw": 64947,
                          "full_name": "Daniel Okonkwo",
                          "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                          "id": "m976sftaw9zr7fe2bnkcma60c58c9cmf",
                          "is_public": true,
                          "jobTitle": "Director of AI",
                          "lastName": "Okonkwo",
                          "last_name": "Okonkwo",
                          "linkedin_url": null,
                          "name": "Daniel Okonkwo",
                          "participant_role": {
                            "core_role": "speaker",
                            "name": "Speaker",
                            "name_plural": "Speakers",
                            "slug": "speaker"
                          },
                          "phone_mobile": null,
                          "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                          "pronouns": null,
                          "salutation": null,
                          "title": "Director of AI",
                          "twitter_url": null,
                          "updated_at": "2026-08-11T13:10:05.999Z",
                          "website_url": null,
                          "workflow_status": null
                        }
                      ],
                      "public_visible": true,
                      "room": {
                        "capacity": 300,
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "id": "js76t15v2t5z854w4ct9t46gxh8c8aac",
                        "name": "Main Stage",
                        "order": 0,
                        "updated_at": "2026-08-11T13:10:05.999Z"
                      },
                      "speakers": [
                        {
                          "about": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                          "bio": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                          "company": "Fathom Robotics",
                          "company_name": "Fathom Robotics",
                          "created_at": "2026-08-11T13:10:05.999Z",
                          "email": "noah.blackwood@example.com",
                          "firstName": "Noah",
                          "first_name": "Noah",
                          "friendly_id": "SPK-32294",
                          "friendly_id_raw": 32294,
                          "full_name": "Noah Blackwood",
                          "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                          "id": "m97ed5bzvtqddq1gm642p216js8c911f",
                          "is_public": true,
                          "jobTitle": "Chief Technology Officer",
                          "lastName": "Blackwood",
                          "last_name": "Blackwood",
                          "linkedin_url": null,
                          "name": "Noah Blackwood",
                          "participant_role": {
                            "core_role": "speaker",
                            "name": "Speaker",
                            "name_plural": "Speakers",
                            "slug": "speaker"
                          },
                          "phone_mobile": null,
                          "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                          "pronouns": null,
                          "salutation": null,
                          "title": "Chief Technology Officer",
                          "twitter_url": null,
                          "updated_at": "2026-08-11T13:10:05.999Z",
                          "website_url": null,
                          "workflow_status": null
                        },
                        {
                          "about": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                          "bio": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                          "company": "Meridian Health",
                          "company_name": "Meridian Health",
                          "created_at": "2026-08-11T13:10:05.999Z",
                          "email": "daniel.okonkwo@example.com",
                          "firstName": "Daniel",
                          "first_name": "Daniel",
                          "friendly_id": "SPK-64947",
                          "friendly_id_raw": 64947,
                          "full_name": "Daniel Okonkwo",
                          "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                          "id": "m976sftaw9zr7fe2bnkcma60c58c9cmf",
                          "is_public": true,
                          "jobTitle": "Director of AI",
                          "lastName": "Okonkwo",
                          "last_name": "Okonkwo",
                          "linkedin_url": null,
                          "name": "Daniel Okonkwo",
                          "participant_role": {
                            "core_role": "speaker",
                            "name": "Speaker",
                            "name_plural": "Speakers",
                            "slug": "speaker"
                          },
                          "phone_mobile": null,
                          "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                          "pronouns": null,
                          "salutation": null,
                          "title": "Director of AI",
                          "twitter_url": null,
                          "updated_at": "2026-08-11T13:10:05.999Z",
                          "website_url": null,
                          "workflow_status": null
                        }
                      ],
                      "startTime": 1791932400000,
                      "starts_at": "2026-10-13T23:00:00.000Z",
                      "status": "accepted",
                      "submittedAt": 1786453805999.9343,
                      "submitter": {
                        "about": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "bio": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "company": "Fathom Robotics",
                        "company_name": "Fathom Robotics",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "email": "noah.blackwood@example.com",
                        "firstName": "Noah",
                        "first_name": "Noah",
                        "friendly_id": "SPK-32294",
                        "friendly_id_raw": 32294,
                        "full_name": "Noah Blackwood",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "id": "m97ed5bzvtqddq1gm642p216js8c911f",
                        "is_public": true,
                        "jobTitle": "Chief Technology Officer",
                        "lastName": "Blackwood",
                        "last_name": "Blackwood",
                        "linkedin_url": null,
                        "name": "Noah Blackwood",
                        "participant_role": null,
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "pronouns": null,
                        "salutation": null,
                        "title": "Chief Technology Officer",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T13:10:05.999Z",
                        "website_url": null,
                        "workflow_status": null
                      },
                      "subsessions": [],
                      "tags": [
                        {
                          "id": "panel",
                          "name": "panel"
                        },
                        {
                          "id": "agents",
                          "name": "agents"
                        }
                      ],
                      "title": "Closing panel: what we got wrong about agents",
                      "track": {
                        "color": "#1E9E6B",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "event_id": "j9722stesd2vbsdnppys47wqe98c8nb0",
                        "id": "kd77jbd8np4qh1xhz2xb85383s8c8c93",
                        "name": "Product",
                        "order": 1,
                        "updated_at": "2026-08-11T13:10:05.999Z"
                      },
                      "trackColor": "#1E9E6B",
                      "updated_at": "2026-08-11T13:10:05.999Z"
                    }
                  ],
                  "event": {
                    "_id": "j9722stesd2vbsdnppys47wqe98c8nb0",
                    "agenda_published_at": "2026-08-06T13:10:05.999Z",
                    "background_url": null,
                    "created_at": "2026-08-11T13:10:05.999Z",
                    "description": "Two days for the people building AI systems that have to work on Monday morning. Practitioner talks on evaluation, agents, retrieval, inference infrastructure and the product decisions in between — no keynote fluff, no vendor pitches.",
                    "endsAt": 1791939600000,
                    "ends_at": "2026-10-14T01:00:00.000Z",
                    "features": {
                      "custom_fields": true,
                      "translated_fields": false,
                      "webhooks": true
                    },
                    "id": "j9722stesd2vbsdnppys47wqe98c8nb0",
                    "logo_url": null,
                    "name": "AI Engineer Summit 2026",
                    "organization_id": "mn7fs8btg5szyhbkqdfhtd4xmn8c8xhg",
                    "portal_settings": {
                      "allow_submission_edits": true,
                      "always_show_tasks": false,
                      "extend_task_deadlines": true
                    },
                    "public_url": "/e/ai-summit-2026",
                    "slug": "ai-summit-2026",
                    "startsAt": 1791820800000,
                    "starts_at": "2026-10-12T16:00:00.000Z",
                    "timezone": "America/Los_Angeles",
                    "type": "Conference",
                    "venue": "Moscone West, San Francisco",
                    "websiteUrl": "https://example.com/ai-summit-2026",
                    "website_url": "https://example.com/ai-summit-2026"
                  },
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 1,
                    "page_size": 1,
                    "totalPages": 6,
                    "totalResults": 6,
                    "total_pages": 6,
                    "total_results": 6
                  },
                  "results": [
                    {
                      "answers": {
                        "description": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today.",
                        "format": "Panel",
                        "language": "English",
                        "level": "Intermediate",
                        "takeaways": "Honest post-mortems from four production agent systems.",
                        "title": "Closing panel: what we got wrong about agents",
                        "track": "Product"
                      },
                      "capacity": 300,
                      "chairpersons": [],
                      "created_at": "2026-08-11T13:10:05.999Z",
                      "custom_fields": [
                        {
                          "created_at": "2026-08-11T13:10:05.999Z",
                          "id": "description",
                          "internal_name": "description",
                          "name": "Session description",
                          "type": "long_text",
                          "value": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today.",
                          "value_raw": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today."
                        },
                        {
                          "created_at": "2026-08-11T13:10:05.999Z",
                          "id": "format",
                          "internal_name": "format",
                          "name": "Format",
                          "type": "dropdown",
                          "value": "Panel",
                          "value_raw": "Panel"
                        }
                      ],
                      "decidedAt": 1785935405999,
                      "decided_at": "2026-08-05T13:10:05.999Z",
                      "deleted_at": null,
                      "description": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today.",
                      "durationMinutes": 60,
                      "duration_minutes": 60,
                      "endTime": 1791936000000,
                      "ends_at": "2026-10-14T00:00:00.000Z",
                      "format": {
                        "id": "Panel",
                        "name": "Panel"
                      },
                      "friendly_id": "SESS-42342",
                      "friendly_id_raw": 42342,
                      "id": "k57b5gt5pefy4jcjg6y6023yss8c9det",
                      "is_abstract": false,
                      "is_public": true,
                      "kind": "session",
                      "language": {
                        "id": "English",
                        "name": "English"
                      },
                      "level": {
                        "id": "Intermediate",
                        "name": "Intermediate"
                      },
                      "location": "Main Stage",
                      "moderators": [],
                      "notified_at": "2026-08-06T13:10:05.999Z",
                      "participants": [
                        {
                          "about": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                          "bio": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                          "company": "Fathom Robotics",
                          "company_name": "Fathom Robotics",
                          "created_at": "2026-08-11T13:10:05.999Z",
                          "email": "noah.blackwood@example.com",
                          "firstName": "Noah",
                          "first_name": "Noah",
                          "friendly_id": "SPK-32294",
                          "friendly_id_raw": 32294,
                          "full_name": "Noah Blackwood",
                          "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                          "id": "m97ed5bzvtqddq1gm642p216js8c911f",
                          "is_public": true,
                          "jobTitle": "Chief Technology Officer",
                          "lastName": "Blackwood",
                          "last_name": "Blackwood",
                          "linkedin_url": null,
                          "name": "Noah Blackwood",
                          "participant_role": {
                            "core_role": "speaker",
                            "name": "Speaker",
                            "name_plural": "Speakers",
                            "slug": "speaker"
                          },
                          "phone_mobile": null,
                          "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                          "pronouns": null,
                          "salutation": null,
                          "title": "Chief Technology Officer",
                          "twitter_url": null,
                          "updated_at": "2026-08-11T13:10:05.999Z",
                          "website_url": null,
                          "workflow_status": null
                        },
                        {
                          "about": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                          "bio": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                          "company": "Meridian Health",
                          "company_name": "Meridian Health",
                          "created_at": "2026-08-11T13:10:05.999Z",
                          "email": "daniel.okonkwo@example.com",
                          "firstName": "Daniel",
                          "first_name": "Daniel",
                          "friendly_id": "SPK-64947",
                          "friendly_id_raw": 64947,
                          "full_name": "Daniel Okonkwo",
                          "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                          "id": "m976sftaw9zr7fe2bnkcma60c58c9cmf",
                          "is_public": true,
                          "jobTitle": "Director of AI",
                          "lastName": "Okonkwo",
                          "last_name": "Okonkwo",
                          "linkedin_url": null,
                          "name": "Daniel Okonkwo",
                          "participant_role": {
                            "core_role": "speaker",
                            "name": "Speaker",
                            "name_plural": "Speakers",
                            "slug": "speaker"
                          },
                          "phone_mobile": null,
                          "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                          "pronouns": null,
                          "salutation": null,
                          "title": "Director of AI",
                          "twitter_url": null,
                          "updated_at": "2026-08-11T13:10:05.999Z",
                          "website_url": null,
                          "workflow_status": null
                        }
                      ],
                      "public_visible": true,
                      "room": {
                        "capacity": 300,
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "id": "js76t15v2t5z854w4ct9t46gxh8c8aac",
                        "name": "Main Stage",
                        "order": 0,
                        "updated_at": "2026-08-11T13:10:05.999Z"
                      },
                      "speakers": [
                        {
                          "about": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                          "bio": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                          "company": "Fathom Robotics",
                          "company_name": "Fathom Robotics",
                          "created_at": "2026-08-11T13:10:05.999Z",
                          "email": "noah.blackwood@example.com",
                          "firstName": "Noah",
                          "first_name": "Noah",
                          "friendly_id": "SPK-32294",
                          "friendly_id_raw": 32294,
                          "full_name": "Noah Blackwood",
                          "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                          "id": "m97ed5bzvtqddq1gm642p216js8c911f",
                          "is_public": true,
                          "jobTitle": "Chief Technology Officer",
                          "lastName": "Blackwood",
                          "last_name": "Blackwood",
                          "linkedin_url": null,
                          "name": "Noah Blackwood",
                          "participant_role": {
                            "core_role": "speaker",
                            "name": "Speaker",
                            "name_plural": "Speakers",
                            "slug": "speaker"
                          },
                          "phone_mobile": null,
                          "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                          "pronouns": null,
                          "salutation": null,
                          "title": "Chief Technology Officer",
                          "twitter_url": null,
                          "updated_at": "2026-08-11T13:10:05.999Z",
                          "website_url": null,
                          "workflow_status": null
                        },
                        {
                          "about": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                          "bio": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                          "company": "Meridian Health",
                          "company_name": "Meridian Health",
                          "created_at": "2026-08-11T13:10:05.999Z",
                          "email": "daniel.okonkwo@example.com",
                          "firstName": "Daniel",
                          "first_name": "Daniel",
                          "friendly_id": "SPK-64947",
                          "friendly_id_raw": 64947,
                          "full_name": "Daniel Okonkwo",
                          "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                          "id": "m976sftaw9zr7fe2bnkcma60c58c9cmf",
                          "is_public": true,
                          "jobTitle": "Director of AI",
                          "lastName": "Okonkwo",
                          "last_name": "Okonkwo",
                          "linkedin_url": null,
                          "name": "Daniel Okonkwo",
                          "participant_role": {
                            "core_role": "speaker",
                            "name": "Speaker",
                            "name_plural": "Speakers",
                            "slug": "speaker"
                          },
                          "phone_mobile": null,
                          "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                          "pronouns": null,
                          "salutation": null,
                          "title": "Director of AI",
                          "twitter_url": null,
                          "updated_at": "2026-08-11T13:10:05.999Z",
                          "website_url": null,
                          "workflow_status": null
                        }
                      ],
                      "startTime": 1791932400000,
                      "starts_at": "2026-10-13T23:00:00.000Z",
                      "status": "accepted",
                      "submittedAt": 1786453805999.9343,
                      "submitter": {
                        "about": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "bio": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "company": "Fathom Robotics",
                        "company_name": "Fathom Robotics",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "email": "noah.blackwood@example.com",
                        "firstName": "Noah",
                        "first_name": "Noah",
                        "friendly_id": "SPK-32294",
                        "friendly_id_raw": 32294,
                        "full_name": "Noah Blackwood",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "id": "m97ed5bzvtqddq1gm642p216js8c911f",
                        "is_public": true,
                        "jobTitle": "Chief Technology Officer",
                        "lastName": "Blackwood",
                        "last_name": "Blackwood",
                        "linkedin_url": null,
                        "name": "Noah Blackwood",
                        "participant_role": null,
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "pronouns": null,
                        "salutation": null,
                        "title": "Chief Technology Officer",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T13:10:05.999Z",
                        "website_url": null,
                        "workflow_status": null
                      },
                      "subsessions": [],
                      "tags": [
                        {
                          "id": "panel",
                          "name": "panel"
                        },
                        {
                          "id": "agents",
                          "name": "agents"
                        }
                      ],
                      "title": "Closing panel: what we got wrong about agents",
                      "track": {
                        "color": "#1E9E6B",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "event_id": "j9722stesd2vbsdnppys47wqe98c8nb0",
                        "id": "kd77jbd8np4qh1xhz2xb85383s8c8c93",
                        "name": "Product",
                        "order": 1,
                        "updated_at": "2026-08-11T13:10:05.999Z"
                      },
                      "trackColor": "#1E9E6B",
                      "updated_at": "2026-08-11T13:10:05.999Z"
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/sessions/{sessionId}": {
      "get": {
        "operationId": "getSession",
        "tags": [
          "Sessions"
        ],
        "summary": "Get a session",
        "description": "One session in full. Soft-deleted sessions read as 404 unless `expand=deleted` is passed. `expand=files` inlines the session's attachments.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:sessions",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/sessionId"
          },
          {
            "$ref": "#/components/parameters/expand"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionEnvelope"
                },
                "example": {
                  "data": {
                    "answers": {
                      "description": "<p>A talk created by the verify script.</p>",
                      "format": "Talk",
                      "language": "English",
                      "level": "Introductory",
                      "title": "Verification Talk",
                      "track": "AI Engineering"
                    },
                    "capacity": 300,
                    "chairpersons": [],
                    "created_at": "2026-08-11T19:27:52.774Z",
                    "custom_fields": [
                      {
                        "created_at": "2026-08-11T19:27:52.774Z",
                        "id": "description",
                        "internal_name": "description",
                        "name": "Session description",
                        "type": "long_text",
                        "value": "<p>A talk created by the verify script.</p>",
                        "value_raw": "<p>A talk created by the verify script.</p>"
                      },
                      {
                        "created_at": "2026-08-11T19:27:52.774Z",
                        "id": "format",
                        "internal_name": "format",
                        "name": "Format",
                        "type": "dropdown",
                        "value": "Talk",
                        "value_raw": "Talk"
                      }
                    ],
                    "decidedAt": 1786476486819,
                    "decided_at": "2026-08-11T19:28:06.819Z",
                    "deleted_at": null,
                    "description": "<p>A talk created by the verify script.</p>",
                    "durationMinutes": 45,
                    "duration_minutes": 45,
                    "endTime": 1791801900000,
                    "ends_at": "2026-10-12T10:45:00.000Z",
                    "format": {
                      "id": "Talk",
                      "name": "Talk"
                    },
                    "friendly_id": "SESS-54160",
                    "friendly_id_raw": 54160,
                    "id": "k575rnyz47j4d4qnh0fh3mh5rh8c9mm8",
                    "is_abstract": true,
                    "is_public": true,
                    "kind": "abstract",
                    "language": {
                      "id": "English",
                      "name": "English"
                    },
                    "level": {
                      "id": "Introductory",
                      "name": "Introductory"
                    },
                    "location": "Main Stage",
                    "moderators": [],
                    "notified_at": "2026-08-11T19:28:06.819Z",
                    "participants": [
                      {
                        "about": "An updated bio from the verify script.",
                        "bio": "An updated bio from the verify script.",
                        "company": null,
                        "company_name": null,
                        "created_at": "2026-08-11T19:27:51.938Z",
                        "email": "verify-e2e-msp1yrr9@example.com",
                        "firstName": "Vera",
                        "first_name": "Vera",
                        "friendly_id": "SPK-68155",
                        "friendly_id_raw": 68155,
                        "full_name": "Vera Efftest",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                        "id": "m975yb2bcxrwfxc33qzmd8pthh8c8pwg",
                        "is_public": true,
                        "jobTitle": "QA Engineer",
                        "lastName": "Efftest",
                        "last_name": "Efftest",
                        "linkedin_url": null,
                        "name": "Vera Efftest",
                        "participant_role": {
                          "core_role": "speaker",
                          "name": "Speaker",
                          "name_plural": "Speakers",
                          "slug": "speaker"
                        },
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                        "pronouns": null,
                        "salutation": null,
                        "title": "QA Engineer",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T19:27:51.938Z",
                        "website_url": null,
                        "workflow_status": null
                      }
                    ],
                    "public_visible": true,
                    "room": {
                      "capacity": 300,
                      "created_at": "2026-08-11T19:27:45.331Z",
                      "id": "js7bf7gcc7h75dees2qgsk7wks8c8yja",
                      "name": "Main Stage",
                      "order": 0,
                      "updated_at": "2026-08-11T19:27:45.331Z"
                    },
                    "speakers": [
                      {
                        "about": "An updated bio from the verify script.",
                        "bio": "An updated bio from the verify script.",
                        "company": null,
                        "company_name": null,
                        "created_at": "2026-08-11T19:27:51.938Z",
                        "email": "verify-e2e-msp1yrr9@example.com",
                        "firstName": "Vera",
                        "first_name": "Vera",
                        "friendly_id": "SPK-68155",
                        "friendly_id_raw": 68155,
                        "full_name": "Vera Efftest",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                        "id": "m975yb2bcxrwfxc33qzmd8pthh8c8pwg",
                        "is_public": true,
                        "jobTitle": "QA Engineer",
                        "lastName": "Efftest",
                        "last_name": "Efftest",
                        "linkedin_url": null,
                        "name": "Vera Efftest",
                        "participant_role": {
                          "core_role": "speaker",
                          "name": "Speaker",
                          "name_plural": "Speakers",
                          "slug": "speaker"
                        },
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                        "pronouns": null,
                        "salutation": null,
                        "title": "QA Engineer",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T19:27:51.938Z",
                        "website_url": null,
                        "workflow_status": null
                      }
                    ],
                    "startTime": 1791799200000,
                    "starts_at": "2026-10-12T10:00:00.000Z",
                    "status": "accepted",
                    "submittedAt": 1786476472774.8613,
                    "submitter": {
                      "about": "An updated bio from the verify script.",
                      "bio": "An updated bio from the verify script.",
                      "company": null,
                      "company_name": null,
                      "created_at": "2026-08-11T19:27:51.938Z",
                      "email": "verify-e2e-msp1yrr9@example.com",
                      "firstName": "Vera",
                      "first_name": "Vera",
                      "friendly_id": "SPK-68155",
                      "friendly_id_raw": 68155,
                      "full_name": "Vera Efftest",
                      "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                      "id": "m975yb2bcxrwfxc33qzmd8pthh8c8pwg",
                      "is_public": true,
                      "jobTitle": "QA Engineer",
                      "lastName": "Efftest",
                      "last_name": "Efftest",
                      "linkedin_url": null,
                      "name": "Vera Efftest",
                      "participant_role": null,
                      "phone_mobile": null,
                      "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                      "pronouns": null,
                      "salutation": null,
                      "title": "QA Engineer",
                      "twitter_url": null,
                      "updated_at": "2026-08-11T19:27:51.938Z",
                      "website_url": null,
                      "workflow_status": null
                    },
                    "subsessions": [],
                    "tags": [],
                    "title": "Verification Talk (edited)",
                    "track": {
                      "color": "#2F5CE0",
                      "created_at": "2026-08-11T19:27:45.331Z",
                      "event_id": "j976eyym787qhaq02v0nea4k7x8c879q",
                      "id": "kd70s9jv39zmvkarkyrjcbk14x8c8g9d",
                      "name": "AI Engineering",
                      "order": 0,
                      "updated_at": "2026-08-11T19:27:45.331Z"
                    },
                    "trackColor": "#2F5CE0",
                    "updated_at": "2026-08-11T19:27:52.774Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "put": {
        "operationId": "updateSession",
        "tags": [
          "Session Writes"
        ],
        "summary": "Update a session",
        "description": "Partial update. Send the `updated_at` you last read for optimistic concurrency — a mismatch answers 409 with the current value rather than silently clobbering someone else's edit.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `session_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:sessions",
        "x-rate-limit-bucket": "session_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/sessionId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SessionWriteBody"
              },
              "example": {
                "title": "Designing agent workflows (revised)",
                "status": "accepted",
                "room_id": "k17abc…",
                "updated_at": "2026-08-11T09:12:44.001Z"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionEnvelope"
                },
                "example": {
                  "data": {
                    "answers": {
                      "description": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today.",
                      "format": "Panel",
                      "language": "English",
                      "level": "Intermediate",
                      "takeaways": "Honest post-mortems from four production agent systems.",
                      "title": "Closing panel: what we got wrong about agents",
                      "track": "Product"
                    },
                    "capacity": 300,
                    "chairpersons": [],
                    "created_at": "2026-08-11T13:10:05.999Z",
                    "custom_fields": [
                      {
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "id": "description",
                        "internal_name": "description",
                        "name": "Session description",
                        "type": "long_text",
                        "value": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today.",
                        "value_raw": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today."
                      },
                      {
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "id": "format",
                        "internal_name": "format",
                        "name": "Format",
                        "type": "dropdown",
                        "value": "Panel",
                        "value_raw": "Panel"
                      }
                    ],
                    "decidedAt": 1785935405999,
                    "decided_at": "2026-08-05T13:10:05.999Z",
                    "deleted_at": null,
                    "description": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today.",
                    "durationMinutes": 60,
                    "duration_minutes": 60,
                    "endTime": 1791936000000,
                    "ends_at": "2026-10-14T00:00:00.000Z",
                    "format": {
                      "id": "Panel",
                      "name": "Panel"
                    },
                    "friendly_id": "SESS-42342",
                    "friendly_id_raw": 42342,
                    "id": "k57b5gt5pefy4jcjg6y6023yss8c9det",
                    "is_abstract": false,
                    "is_public": true,
                    "kind": "session",
                    "language": {
                      "id": "English",
                      "name": "English"
                    },
                    "level": {
                      "id": "Intermediate",
                      "name": "Intermediate"
                    },
                    "location": "Main Stage",
                    "moderators": [],
                    "notified_at": "2026-08-06T13:10:05.999Z",
                    "participants": [
                      {
                        "about": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "bio": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "company": "Fathom Robotics",
                        "company_name": "Fathom Robotics",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "email": "noah.blackwood@example.com",
                        "firstName": "Noah",
                        "first_name": "Noah",
                        "friendly_id": "SPK-32294",
                        "friendly_id_raw": 32294,
                        "full_name": "Noah Blackwood",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "id": "m97ed5bzvtqddq1gm642p216js8c911f",
                        "is_public": true,
                        "jobTitle": "Chief Technology Officer",
                        "lastName": "Blackwood",
                        "last_name": "Blackwood",
                        "linkedin_url": null,
                        "name": "Noah Blackwood",
                        "participant_role": {
                          "core_role": "speaker",
                          "name": "Speaker",
                          "name_plural": "Speakers",
                          "slug": "speaker"
                        },
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "pronouns": null,
                        "salutation": null,
                        "title": "Chief Technology Officer",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T13:10:05.999Z",
                        "website_url": null,
                        "workflow_status": null
                      },
                      {
                        "about": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                        "bio": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                        "company": "Meridian Health",
                        "company_name": "Meridian Health",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "email": "daniel.okonkwo@example.com",
                        "firstName": "Daniel",
                        "first_name": "Daniel",
                        "friendly_id": "SPK-64947",
                        "friendly_id_raw": 64947,
                        "full_name": "Daniel Okonkwo",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                        "id": "m976sftaw9zr7fe2bnkcma60c58c9cmf",
                        "is_public": true,
                        "jobTitle": "Director of AI",
                        "lastName": "Okonkwo",
                        "last_name": "Okonkwo",
                        "linkedin_url": null,
                        "name": "Daniel Okonkwo",
                        "participant_role": {
                          "core_role": "speaker",
                          "name": "Speaker",
                          "name_plural": "Speakers",
                          "slug": "speaker"
                        },
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                        "pronouns": null,
                        "salutation": null,
                        "title": "Director of AI",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T13:10:05.999Z",
                        "website_url": null,
                        "workflow_status": null
                      }
                    ],
                    "public_visible": true,
                    "room": {
                      "capacity": 300,
                      "created_at": "2026-08-11T13:10:05.999Z",
                      "id": "js76t15v2t5z854w4ct9t46gxh8c8aac",
                      "name": "Main Stage",
                      "order": 0,
                      "updated_at": "2026-08-11T13:10:05.999Z"
                    },
                    "speakers": [
                      {
                        "about": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "bio": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "company": "Fathom Robotics",
                        "company_name": "Fathom Robotics",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "email": "noah.blackwood@example.com",
                        "firstName": "Noah",
                        "first_name": "Noah",
                        "friendly_id": "SPK-32294",
                        "friendly_id_raw": 32294,
                        "full_name": "Noah Blackwood",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "id": "m97ed5bzvtqddq1gm642p216js8c911f",
                        "is_public": true,
                        "jobTitle": "Chief Technology Officer",
                        "lastName": "Blackwood",
                        "last_name": "Blackwood",
                        "linkedin_url": null,
                        "name": "Noah Blackwood",
                        "participant_role": {
                          "core_role": "speaker",
                          "name": "Speaker",
                          "name_plural": "Speakers",
                          "slug": "speaker"
                        },
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "pronouns": null,
                        "salutation": null,
                        "title": "Chief Technology Officer",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T13:10:05.999Z",
                        "website_url": null,
                        "workflow_status": null
                      },
                      {
                        "about": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                        "bio": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                        "company": "Meridian Health",
                        "company_name": "Meridian Health",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "email": "daniel.okonkwo@example.com",
                        "firstName": "Daniel",
                        "first_name": "Daniel",
                        "friendly_id": "SPK-64947",
                        "friendly_id_raw": 64947,
                        "full_name": "Daniel Okonkwo",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                        "id": "m976sftaw9zr7fe2bnkcma60c58c9cmf",
                        "is_public": true,
                        "jobTitle": "Director of AI",
                        "lastName": "Okonkwo",
                        "last_name": "Okonkwo",
                        "linkedin_url": null,
                        "name": "Daniel Okonkwo",
                        "participant_role": {
                          "core_role": "speaker",
                          "name": "Speaker",
                          "name_plural": "Speakers",
                          "slug": "speaker"
                        },
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                        "pronouns": null,
                        "salutation": null,
                        "title": "Director of AI",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T13:10:05.999Z",
                        "website_url": null,
                        "workflow_status": null
                      }
                    ],
                    "startTime": 1791932400000,
                    "starts_at": "2026-10-13T23:00:00.000Z",
                    "status": "accepted",
                    "submittedAt": 1786453805999.9343,
                    "submitter": {
                      "about": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                      "bio": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                      "company": "Fathom Robotics",
                      "company_name": "Fathom Robotics",
                      "created_at": "2026-08-11T13:10:05.999Z",
                      "email": "noah.blackwood@example.com",
                      "firstName": "Noah",
                      "first_name": "Noah",
                      "friendly_id": "SPK-32294",
                      "friendly_id_raw": 32294,
                      "full_name": "Noah Blackwood",
                      "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                      "id": "m97ed5bzvtqddq1gm642p216js8c911f",
                      "is_public": true,
                      "jobTitle": "Chief Technology Officer",
                      "lastName": "Blackwood",
                      "last_name": "Blackwood",
                      "linkedin_url": null,
                      "name": "Noah Blackwood",
                      "participant_role": null,
                      "phone_mobile": null,
                      "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                      "pronouns": null,
                      "salutation": null,
                      "title": "Chief Technology Officer",
                      "twitter_url": null,
                      "updated_at": "2026-08-11T13:10:05.999Z",
                      "website_url": null,
                      "workflow_status": null
                    },
                    "subsessions": [],
                    "tags": [
                      {
                        "id": "panel",
                        "name": "panel"
                      },
                      {
                        "id": "agents",
                        "name": "agents"
                      }
                    ],
                    "title": "Closing panel: what we got wrong about agents",
                    "track": {
                      "color": "#1E9E6B",
                      "created_at": "2026-08-11T13:10:05.999Z",
                      "event_id": "j9722stesd2vbsdnppys47wqe98c8nb0",
                      "id": "kd77jbd8np4qh1xhz2xb85383s8c8c93",
                      "name": "Product",
                      "order": 1,
                      "updated_at": "2026-08-11T13:10:05.999Z"
                    },
                    "trackColor": "#1E9E6B",
                    "updated_at": "2026-08-11T13:10:05.999Z"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "409": {
            "$ref": "#/components/responses/E409"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "delete": {
        "operationId": "deleteSession",
        "tags": [
          "Session Writes"
        ],
        "summary": "Soft-delete a session",
        "description": "Marks the session deleted. It leaves every listing and reads as 404, and nothing is destroyed — `POST /restore` brings it back with its participants, answers and files intact. Requires the admin role.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `session_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:sessions",
        "x-rate-limit-bucket": "session_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/sessionId"
          }
        ],
        "responses": {
          "204": {
            "description": "No content.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/sessions/{sessionId}/fields": {
      "put": {
        "operationId": "updateSessionFields",
        "tags": [
          "Session Writes"
        ],
        "summary": "Update session custom fields",
        "description": "Writes custom-field values without touching anything else on the session. Keys are field `internal_name`s from `GET /fields`; unknown keys are stored and returned rather than dropped.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `session_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:sessions",
        "x-rate-limit-bucket": "session_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/sessionId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CustomFieldsBody"
              },
              "example": {
                "custom_fields": {
                  "takeaways": "Three patterns and one anti-pattern.",
                  "prior_talks": [
                    "SREcon 2025",
                    "KubeCon 2024"
                  ]
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionEnvelope"
                },
                "example": {
                  "data": {
                    "answers": {
                      "description": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today.",
                      "format": "Panel",
                      "language": "English",
                      "level": "Intermediate",
                      "takeaways": "Honest post-mortems from four production agent systems.",
                      "title": "Closing panel: what we got wrong about agents",
                      "track": "Product"
                    },
                    "capacity": 300,
                    "chairpersons": [],
                    "created_at": "2026-08-11T13:10:05.999Z",
                    "custom_fields": [
                      {
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "id": "description",
                        "internal_name": "description",
                        "name": "Session description",
                        "type": "long_text",
                        "value": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today.",
                        "value_raw": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today."
                      },
                      {
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "id": "format",
                        "internal_name": "format",
                        "name": "Format",
                        "type": "dropdown",
                        "value": "Panel",
                        "value_raw": "Panel"
                      }
                    ],
                    "decidedAt": 1785935405999,
                    "decided_at": "2026-08-05T13:10:05.999Z",
                    "deleted_at": null,
                    "description": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today.",
                    "durationMinutes": 60,
                    "duration_minutes": 60,
                    "endTime": 1791936000000,
                    "ends_at": "2026-10-14T00:00:00.000Z",
                    "format": {
                      "id": "Panel",
                      "name": "Panel"
                    },
                    "friendly_id": "SESS-42342",
                    "friendly_id_raw": 42342,
                    "id": "k57b5gt5pefy4jcjg6y6023yss8c9det",
                    "is_abstract": false,
                    "is_public": true,
                    "kind": "session",
                    "language": {
                      "id": "English",
                      "name": "English"
                    },
                    "level": {
                      "id": "Intermediate",
                      "name": "Intermediate"
                    },
                    "location": "Main Stage",
                    "moderators": [],
                    "notified_at": "2026-08-06T13:10:05.999Z",
                    "participants": [
                      {
                        "about": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "bio": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "company": "Fathom Robotics",
                        "company_name": "Fathom Robotics",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "email": "noah.blackwood@example.com",
                        "firstName": "Noah",
                        "first_name": "Noah",
                        "friendly_id": "SPK-32294",
                        "friendly_id_raw": 32294,
                        "full_name": "Noah Blackwood",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "id": "m97ed5bzvtqddq1gm642p216js8c911f",
                        "is_public": true,
                        "jobTitle": "Chief Technology Officer",
                        "lastName": "Blackwood",
                        "last_name": "Blackwood",
                        "linkedin_url": null,
                        "name": "Noah Blackwood",
                        "participant_role": {
                          "core_role": "speaker",
                          "name": "Speaker",
                          "name_plural": "Speakers",
                          "slug": "speaker"
                        },
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "pronouns": null,
                        "salutation": null,
                        "title": "Chief Technology Officer",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T13:10:05.999Z",
                        "website_url": null,
                        "workflow_status": null
                      },
                      {
                        "about": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                        "bio": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                        "company": "Meridian Health",
                        "company_name": "Meridian Health",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "email": "daniel.okonkwo@example.com",
                        "firstName": "Daniel",
                        "first_name": "Daniel",
                        "friendly_id": "SPK-64947",
                        "friendly_id_raw": 64947,
                        "full_name": "Daniel Okonkwo",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                        "id": "m976sftaw9zr7fe2bnkcma60c58c9cmf",
                        "is_public": true,
                        "jobTitle": "Director of AI",
                        "lastName": "Okonkwo",
                        "last_name": "Okonkwo",
                        "linkedin_url": null,
                        "name": "Daniel Okonkwo",
                        "participant_role": {
                          "core_role": "speaker",
                          "name": "Speaker",
                          "name_plural": "Speakers",
                          "slug": "speaker"
                        },
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                        "pronouns": null,
                        "salutation": null,
                        "title": "Director of AI",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T13:10:05.999Z",
                        "website_url": null,
                        "workflow_status": null
                      }
                    ],
                    "public_visible": true,
                    "room": {
                      "capacity": 300,
                      "created_at": "2026-08-11T13:10:05.999Z",
                      "id": "js76t15v2t5z854w4ct9t46gxh8c8aac",
                      "name": "Main Stage",
                      "order": 0,
                      "updated_at": "2026-08-11T13:10:05.999Z"
                    },
                    "speakers": [
                      {
                        "about": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "bio": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "company": "Fathom Robotics",
                        "company_name": "Fathom Robotics",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "email": "noah.blackwood@example.com",
                        "firstName": "Noah",
                        "first_name": "Noah",
                        "friendly_id": "SPK-32294",
                        "friendly_id_raw": 32294,
                        "full_name": "Noah Blackwood",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "id": "m97ed5bzvtqddq1gm642p216js8c911f",
                        "is_public": true,
                        "jobTitle": "Chief Technology Officer",
                        "lastName": "Blackwood",
                        "last_name": "Blackwood",
                        "linkedin_url": null,
                        "name": "Noah Blackwood",
                        "participant_role": {
                          "core_role": "speaker",
                          "name": "Speaker",
                          "name_plural": "Speakers",
                          "slug": "speaker"
                        },
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "pronouns": null,
                        "salutation": null,
                        "title": "Chief Technology Officer",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T13:10:05.999Z",
                        "website_url": null,
                        "workflow_status": null
                      },
                      {
                        "about": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                        "bio": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                        "company": "Meridian Health",
                        "company_name": "Meridian Health",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "email": "daniel.okonkwo@example.com",
                        "firstName": "Daniel",
                        "first_name": "Daniel",
                        "friendly_id": "SPK-64947",
                        "friendly_id_raw": 64947,
                        "full_name": "Daniel Okonkwo",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                        "id": "m976sftaw9zr7fe2bnkcma60c58c9cmf",
                        "is_public": true,
                        "jobTitle": "Director of AI",
                        "lastName": "Okonkwo",
                        "last_name": "Okonkwo",
                        "linkedin_url": null,
                        "name": "Daniel Okonkwo",
                        "participant_role": {
                          "core_role": "speaker",
                          "name": "Speaker",
                          "name_plural": "Speakers",
                          "slug": "speaker"
                        },
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                        "pronouns": null,
                        "salutation": null,
                        "title": "Director of AI",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T13:10:05.999Z",
                        "website_url": null,
                        "workflow_status": null
                      }
                    ],
                    "startTime": 1791932400000,
                    "starts_at": "2026-10-13T23:00:00.000Z",
                    "status": "accepted",
                    "submittedAt": 1786453805999.9343,
                    "submitter": {
                      "about": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                      "bio": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                      "company": "Fathom Robotics",
                      "company_name": "Fathom Robotics",
                      "created_at": "2026-08-11T13:10:05.999Z",
                      "email": "noah.blackwood@example.com",
                      "firstName": "Noah",
                      "first_name": "Noah",
                      "friendly_id": "SPK-32294",
                      "friendly_id_raw": 32294,
                      "full_name": "Noah Blackwood",
                      "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                      "id": "m97ed5bzvtqddq1gm642p216js8c911f",
                      "is_public": true,
                      "jobTitle": "Chief Technology Officer",
                      "lastName": "Blackwood",
                      "last_name": "Blackwood",
                      "linkedin_url": null,
                      "name": "Noah Blackwood",
                      "participant_role": null,
                      "phone_mobile": null,
                      "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                      "pronouns": null,
                      "salutation": null,
                      "title": "Chief Technology Officer",
                      "twitter_url": null,
                      "updated_at": "2026-08-11T13:10:05.999Z",
                      "website_url": null,
                      "workflow_status": null
                    },
                    "subsessions": [],
                    "tags": [
                      {
                        "id": "panel",
                        "name": "panel"
                      },
                      {
                        "id": "agents",
                        "name": "agents"
                      }
                    ],
                    "title": "Closing panel: what we got wrong about agents",
                    "track": {
                      "color": "#1E9E6B",
                      "created_at": "2026-08-11T13:10:05.999Z",
                      "event_id": "j9722stesd2vbsdnppys47wqe98c8nb0",
                      "id": "kd77jbd8np4qh1xhz2xb85383s8c8c93",
                      "name": "Product",
                      "order": 1,
                      "updated_at": "2026-08-11T13:10:05.999Z"
                    },
                    "trackColor": "#1E9E6B",
                    "updated_at": "2026-08-11T13:10:05.999Z"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/sessions/{sessionId}/files": {
      "get": {
        "operationId": "listSessionFiles",
        "tags": [
          "Session Files"
        ],
        "summary": "List files attached to a session",
        "description": "Completed files only, latest version per file group. Incomplete two-phase uploads and soft-deleted files are omitted.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:sessions",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/sessionId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileListEnvelope"
                },
                "example": {
                  "data": [
                    {
                      "id": "k67abc…",
                      "url": "https://your-deployment.convex.site/api/storage/9f2c…",
                      "title": "Keynote deck",
                      "filename": "keynote-slides.pptx",
                      "size": 18432000,
                      "mimetype": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
                      "version": 2,
                      "approval_status": "approved",
                      "review_note": null,
                      "session_id": "k17abc…",
                      "assigned_participant_id": "k57abc…",
                      "assigned_participant_email": "grace@example.com",
                      "assigned_participant_name": "Grace Hopper",
                      "created_at": "2026-08-09T14:22:07.311Z",
                      "updated_at": "2026-08-09T14:22:07.311Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "post": {
        "operationId": "initiateSessionFileUpload",
        "tags": [
          "Session Files"
        ],
        "summary": "Initiate a session file upload",
        "description": "Two-phase upload for large files. Returns an id and an `upload.url` on this same origin: PUT the bytes there, then POST `/complete`. Unlike a presigned S3 URL the upload leg is authenticated with your ordinary API key.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `session_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:sessions",
        "x-rate-limit-bucket": "session_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/sessionId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SessionFileCreateBody"
              },
              "example": {
                "filename": "keynote-slides.pptx",
                "content_type": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
                "size_bytes": 184320000,
                "title": "Keynote deck (final)"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileUploadTicket"
                },
                "example": {
                  "data": {
                    "id": "k67abc…",
                    "filename": "keynote-slides.pptx",
                    "title": "Keynote deck (final)",
                    "upload": {
                      "url": "https://your-deployment.convex.site/v1/event/ai-summit-2026/sessions/k17abc…/files/k67abc…/bytes",
                      "method": "PUT",
                      "headers": {
                        "Content-Type": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
                        "Authorization": "Bearer <your API key>"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/sessions/{sessionId}/files/{fileId}": {
      "put": {
        "operationId": "updateSessionFile",
        "tags": [
          "Session Files"
        ],
        "summary": "Update session file metadata",
        "description": "Changes the display title and/or the participant the file is assigned to. Does not touch the bytes — use `/replace` for that.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `session_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:sessions",
        "x-rate-limit-bucket": "session_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/sessionId"
          },
          {
            "$ref": "#/components/parameters/fileId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SessionFileUpdateBody"
              },
              "example": {
                "title": "Keynote deck (final)",
                "assigned_participant_id": "k57abc…"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileEnvelope"
                },
                "example": {
                  "data": {
                    "id": "k67abc…",
                    "url": "https://your-deployment.convex.site/api/storage/9f2c…",
                    "title": "Keynote deck (final)",
                    "filename": "keynote-slides.pptx",
                    "size": 18432000,
                    "mimetype": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
                    "version": 2,
                    "approval_status": "approved",
                    "review_note": null,
                    "session_id": "k17abc…",
                    "assigned_participant_id": "k57abc…",
                    "assigned_participant_email": "grace@example.com",
                    "assigned_participant_name": "Grace Hopper",
                    "created_at": "2026-08-09T14:22:07.311Z",
                    "updated_at": "2026-08-09T14:22:07.311Z"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "delete": {
        "operationId": "deleteSessionFile",
        "tags": [
          "Session Files"
        ],
        "summary": "Delete a session file",
        "description": "Soft-deletes the attachment; the bytes are swept later.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `session_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:sessions",
        "x-rate-limit-bucket": "session_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/sessionId"
          },
          {
            "$ref": "#/components/parameters/fileId"
          }
        ],
        "responses": {
          "204": {
            "description": "No content.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/sessions/{sessionId}/files/{fileId}/bytes": {
      "put": {
        "operationId": "putSessionFileBytes",
        "tags": [
          "Session Files"
        ],
        "summary": "Upload the bytes for an initiated file",
        "description": "The upload leg of the two-phase flow. Send the raw file as the request body. Re-PUTting replaces the pending bytes and discards the superseded blob.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.",
        "x-required-scope": "write:sessions",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/sessionId"
          },
          {
            "$ref": "#/components/parameters/fileId"
          }
        ],
        "requestBody": {
          "required": true,
          "description": "The raw file bytes.",
          "content": {
            "application/octet-stream": {
              "schema": {
                "type": "string",
                "format": "binary"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileBytesReceipt"
                },
                "example": {
                  "data": {
                    "id": "k67abc…",
                    "size": 184320000,
                    "received": true
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/sessions/{sessionId}/files/{fileId}/complete": {
      "post": {
        "operationId": "completeSessionFileUpload",
        "tags": [
          "Session Files"
        ],
        "summary": "Finalize a session file upload",
        "description": "Promotes an uploaded blob into a real attachment on the session. Fails with 400 if no bytes were received.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `session_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:sessions",
        "x-rate-limit-bucket": "session_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/sessionId"
          },
          {
            "$ref": "#/components/parameters/fileId"
          }
        ],
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileEnvelope"
                },
                "example": {
                  "data": {
                    "id": "k67abc…",
                    "url": "https://your-deployment.convex.site/api/storage/9f2c…",
                    "title": "Keynote deck",
                    "filename": "keynote-slides.pptx",
                    "size": 18432000,
                    "mimetype": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
                    "version": 2,
                    "approval_status": "approved",
                    "review_note": null,
                    "session_id": "k17abc…",
                    "assigned_participant_id": "k57abc…",
                    "assigned_participant_email": "grace@example.com",
                    "assigned_participant_name": "Grace Hopper",
                    "created_at": "2026-08-09T14:22:07.311Z",
                    "updated_at": "2026-08-09T14:22:07.311Z"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/sessions/{sessionId}/files/{fileId}/replace": {
      "post": {
        "operationId": "replaceSessionFile",
        "tags": [
          "Session Files"
        ],
        "summary": "Replace session file bytes",
        "description": "Starts a two-phase upload that supersedes an existing file, bumping its version. The previous version is retired when the replacement completes.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `session_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:sessions",
        "x-rate-limit-bucket": "session_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/sessionId"
          },
          {
            "$ref": "#/components/parameters/fileId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SessionFileCreateBody"
              },
              "example": {
                "filename": "keynote-slides-v2.pptx",
                "content_type": "application/vnd.openxmlformats-officedocument.presentationml.presentation"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileUploadTicket"
                },
                "example": {
                  "data": {
                    "id": "k67def…",
                    "replaces": "k67abc…",
                    "upload": {
                      "url": "https://your-deployment.convex.site/v1/event/ai-summit-2026/sessions/k17abc…/files/k67def…/bytes",
                      "method": "PUT",
                      "headers": {
                        "Content-Type": "application/vnd.openxmlformats-officedocument.presentationml.presentation"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/sessions/{sessionId}/files/upload": {
      "post": {
        "operationId": "uploadSessionFile",
        "tags": [
          "Session Files"
        ],
        "summary": "Upload a session file (simple)",
        "description": "One multipart request, up to 50 MB. The field name must be `file`. Size and MIME type are read from the bytes. For anything larger use the two-phase flow.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `session_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:sessions",
        "x-rate-limit-bucket": "session_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/sessionId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "multipart/form-data": {
              "schema": {
                "$ref": "#/components/schemas/SessionFileUploadForm"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FileEnvelope"
                },
                "example": {
                  "data": {
                    "id": "k67abc…",
                    "url": "https://your-deployment.convex.site/api/storage/9f2c…",
                    "title": "Keynote deck",
                    "filename": "keynote-slides.pptx",
                    "size": 18432000,
                    "mimetype": "application/vnd.openxmlformats-officedocument.presentationml.presentation",
                    "version": 2,
                    "approval_status": "approved",
                    "review_note": null,
                    "session_id": "k17abc…",
                    "assigned_participant_id": "k57abc…",
                    "assigned_participant_email": "grace@example.com",
                    "assigned_participant_name": "Grace Hopper",
                    "created_at": "2026-08-09T14:22:07.311Z",
                    "updated_at": "2026-08-09T14:22:07.311Z"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "413": {
            "$ref": "#/components/responses/E413"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/sessions/{sessionId}/participants": {
      "get": {
        "operationId": "listSessionParticipants",
        "tags": [
          "Sessions"
        ],
        "summary": "List a session's participants",
        "description": "The line-up in running order, each entry carrying its `participant_id`, `role` and the speaker's full profile.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:contacts` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:contacts",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/sessionId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ParticipantListEnvelope"
                },
                "example": {
                  "data": [
                    {
                      "about": "An updated bio from the verify script.",
                      "bio": "An updated bio from the verify script.",
                      "company": null,
                      "company_name": null,
                      "created_at": "2026-08-11T19:27:51.938Z",
                      "email": "verify-e2e-msp1yrr9@example.com",
                      "firstName": "Vera",
                      "first_name": "Vera",
                      "friendly_id": "SPK-68155",
                      "friendly_id_raw": 68155,
                      "full_name": "Vera Efftest",
                      "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                      "id": "m975yb2bcxrwfxc33qzmd8pthh8c8pwg",
                      "is_public": true,
                      "jobTitle": "QA Engineer",
                      "lastName": "Efftest",
                      "last_name": "Efftest",
                      "linkedin_url": null,
                      "name": "Vera Efftest",
                      "order": 0,
                      "participant_id": "md7bt0zg68xr5b3nbc0tcnyezn8c9tc3",
                      "participant_role": {
                        "core_role": "speaker",
                        "name": "Speaker",
                        "name_plural": "Speakers",
                        "slug": "speaker"
                      },
                      "phone_mobile": null,
                      "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                      "pronouns": null,
                      "role": "speaker",
                      "salutation": null,
                      "session_id": "k575rnyz47j4d4qnh0fh3mh5rh8c9mm8",
                      "title": "QA Engineer",
                      "twitter_url": null,
                      "updated_at": "2026-08-11T19:27:51.938Z",
                      "website_url": null,
                      "workflow_status": null
                    }
                  ],
                  "results": [
                    {
                      "about": "An updated bio from the verify script.",
                      "bio": "An updated bio from the verify script.",
                      "company": null,
                      "company_name": null,
                      "created_at": "2026-08-11T19:27:51.938Z",
                      "email": "verify-e2e-msp1yrr9@example.com",
                      "firstName": "Vera",
                      "first_name": "Vera",
                      "friendly_id": "SPK-68155",
                      "friendly_id_raw": 68155,
                      "full_name": "Vera Efftest",
                      "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                      "id": "m975yb2bcxrwfxc33qzmd8pthh8c8pwg",
                      "is_public": true,
                      "jobTitle": "QA Engineer",
                      "lastName": "Efftest",
                      "last_name": "Efftest",
                      "linkedin_url": null,
                      "name": "Vera Efftest",
                      "order": 0,
                      "participant_id": "md7bt0zg68xr5b3nbc0tcnyezn8c9tc3",
                      "participant_role": {
                        "core_role": "speaker",
                        "name": "Speaker",
                        "name_plural": "Speakers",
                        "slug": "speaker"
                      },
                      "phone_mobile": null,
                      "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/cda7b7ef-4a5a-43b4-89e7-98dea8ab7040",
                      "pronouns": null,
                      "role": "speaker",
                      "salutation": null,
                      "session_id": "k575rnyz47j4d4qnh0fh3mh5rh8c9mm8",
                      "title": "QA Engineer",
                      "twitter_url": null,
                      "updated_at": "2026-08-11T19:27:51.938Z",
                      "website_url": null,
                      "workflow_status": null
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "post": {
        "operationId": "addSessionParticipant",
        "tags": [
          "Session Writes"
        ],
        "summary": "Attach a speaker to a session",
        "description": "Adds someone to the line-up by `speaker_id`, or by `email` (with `first_name` for a person this event has never seen — they are created). Idempotent: re-adding with a different `role` moves them to it rather than failing a sync that ran twice. Emits `session.speaker.attached`.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `session_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:sessions",
        "x-rate-limit-bucket": "session_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/sessionId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ParticipantWriteBody"
              },
              "example": {
                "email": "grace@example.com",
                "first_name": "Grace",
                "last_name": "Hopper",
                "role": "speaker"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ParticipantEnvelope"
                },
                "example": {
                  "data": {
                    "about": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                    "bio": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                    "company": "Fathom Robotics",
                    "company_name": "Fathom Robotics",
                    "created_at": "2026-08-11T13:14:41.555Z",
                    "email": "noah.blackwood@example.com",
                    "firstName": "Noah",
                    "first_name": "Noah",
                    "friendly_id": "SPK-50650",
                    "friendly_id_raw": 50650,
                    "full_name": "Noah Blackwood",
                    "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/23ea9af3-02bc-4e15-b214-a392fc89bdf4",
                    "id": "m97bcdd31cc5a7mq7h171hqcj58c9w5v",
                    "is_public": true,
                    "jobTitle": "Chief Technology Officer",
                    "lastName": "Blackwood",
                    "last_name": "Blackwood",
                    "linkedin_url": null,
                    "name": "Noah Blackwood",
                    "order": 0,
                    "participant_id": "md72yph0gwgq1s7ejxmz6vsg6h8c8qjb",
                    "participant_role": {
                      "core_role": "speaker",
                      "name": "Speaker",
                      "name_plural": "Speakers",
                      "slug": "speaker"
                    },
                    "phone_mobile": null,
                    "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/23ea9af3-02bc-4e15-b214-a392fc89bdf4",
                    "pronouns": null,
                    "role": "speaker",
                    "salutation": null,
                    "session_id": "k571pp0cd1ek2fw0zjjsjb1q858c83fx",
                    "title": "Chief Technology Officer",
                    "twitter_url": null,
                    "updated_at": "2026-08-11T13:14:41.555Z",
                    "website_url": null,
                    "workflow_status": null
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/sessions/{sessionId}/participants/{speakerId}": {
      "delete": {
        "operationId": "removeSessionParticipant",
        "tags": [
          "Session Writes"
        ],
        "summary": "Detach a speaker from a session",
        "description": "Takes someone off this session's line-up. The person themselves is left alone — they may be speaking on something else, and their portal, tasks and files are theirs. Emits `session.speaker.detached`.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `session_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:sessions",
        "x-rate-limit-bucket": "session_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/sessionId"
          },
          {
            "$ref": "#/components/parameters/speakerId"
          }
        ],
        "responses": {
          "204": {
            "description": "No content.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/sessions/{sessionId}/restore": {
      "post": {
        "operationId": "restoreSession",
        "tags": [
          "Session Writes"
        ],
        "summary": "Restore a deleted session",
        "description": "Undoes a soft delete. Requires the admin role.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `session_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:sessions",
        "x-rate-limit-bucket": "session_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/sessionId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionEnvelope"
                },
                "example": {
                  "data": {
                    "answers": {
                      "description": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today.",
                      "format": "Panel",
                      "language": "English",
                      "level": "Intermediate",
                      "takeaways": "Honest post-mortems from four production agent systems.",
                      "title": "Closing panel: what we got wrong about agents",
                      "track": "Product"
                    },
                    "capacity": 300,
                    "chairpersons": [],
                    "created_at": "2026-08-11T13:10:05.999Z",
                    "custom_fields": [
                      {
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "id": "description",
                        "internal_name": "description",
                        "name": "Session description",
                        "type": "long_text",
                        "value": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today.",
                        "value_raw": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today."
                      },
                      {
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "id": "format",
                        "internal_name": "format",
                        "name": "Format",
                        "type": "dropdown",
                        "value": "Panel",
                        "value_raw": "Panel"
                      }
                    ],
                    "decidedAt": 1785935405999,
                    "decided_at": "2026-08-05T13:10:05.999Z",
                    "deleted_at": null,
                    "description": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today.",
                    "durationMinutes": 60,
                    "duration_minutes": 60,
                    "endTime": 1791936000000,
                    "ends_at": "2026-10-14T00:00:00.000Z",
                    "format": {
                      "id": "Panel",
                      "name": "Panel"
                    },
                    "friendly_id": "SESS-42342",
                    "friendly_id_raw": 42342,
                    "id": "k57b5gt5pefy4jcjg6y6023yss8c9det",
                    "is_abstract": false,
                    "is_public": true,
                    "kind": "session",
                    "language": {
                      "id": "English",
                      "name": "English"
                    },
                    "level": {
                      "id": "Intermediate",
                      "name": "Intermediate"
                    },
                    "location": "Main Stage",
                    "moderators": [],
                    "notified_at": "2026-08-06T13:10:05.999Z",
                    "participants": [
                      {
                        "about": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "bio": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "company": "Fathom Robotics",
                        "company_name": "Fathom Robotics",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "email": "noah.blackwood@example.com",
                        "firstName": "Noah",
                        "first_name": "Noah",
                        "friendly_id": "SPK-32294",
                        "friendly_id_raw": 32294,
                        "full_name": "Noah Blackwood",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "id": "m97ed5bzvtqddq1gm642p216js8c911f",
                        "is_public": true,
                        "jobTitle": "Chief Technology Officer",
                        "lastName": "Blackwood",
                        "last_name": "Blackwood",
                        "linkedin_url": null,
                        "name": "Noah Blackwood",
                        "participant_role": {
                          "core_role": "speaker",
                          "name": "Speaker",
                          "name_plural": "Speakers",
                          "slug": "speaker"
                        },
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "pronouns": null,
                        "salutation": null,
                        "title": "Chief Technology Officer",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T13:10:05.999Z",
                        "website_url": null,
                        "workflow_status": null
                      },
                      {
                        "about": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                        "bio": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                        "company": "Meridian Health",
                        "company_name": "Meridian Health",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "email": "daniel.okonkwo@example.com",
                        "firstName": "Daniel",
                        "first_name": "Daniel",
                        "friendly_id": "SPK-64947",
                        "friendly_id_raw": 64947,
                        "full_name": "Daniel Okonkwo",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                        "id": "m976sftaw9zr7fe2bnkcma60c58c9cmf",
                        "is_public": true,
                        "jobTitle": "Director of AI",
                        "lastName": "Okonkwo",
                        "last_name": "Okonkwo",
                        "linkedin_url": null,
                        "name": "Daniel Okonkwo",
                        "participant_role": {
                          "core_role": "speaker",
                          "name": "Speaker",
                          "name_plural": "Speakers",
                          "slug": "speaker"
                        },
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                        "pronouns": null,
                        "salutation": null,
                        "title": "Director of AI",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T13:10:05.999Z",
                        "website_url": null,
                        "workflow_status": null
                      }
                    ],
                    "public_visible": true,
                    "room": {
                      "capacity": 300,
                      "created_at": "2026-08-11T13:10:05.999Z",
                      "id": "js76t15v2t5z854w4ct9t46gxh8c8aac",
                      "name": "Main Stage",
                      "order": 0,
                      "updated_at": "2026-08-11T13:10:05.999Z"
                    },
                    "speakers": [
                      {
                        "about": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "bio": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "company": "Fathom Robotics",
                        "company_name": "Fathom Robotics",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "email": "noah.blackwood@example.com",
                        "firstName": "Noah",
                        "first_name": "Noah",
                        "friendly_id": "SPK-32294",
                        "friendly_id_raw": 32294,
                        "full_name": "Noah Blackwood",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "id": "m97ed5bzvtqddq1gm642p216js8c911f",
                        "is_public": true,
                        "jobTitle": "Chief Technology Officer",
                        "lastName": "Blackwood",
                        "last_name": "Blackwood",
                        "linkedin_url": null,
                        "name": "Noah Blackwood",
                        "participant_role": {
                          "core_role": "speaker",
                          "name": "Speaker",
                          "name_plural": "Speakers",
                          "slug": "speaker"
                        },
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "pronouns": null,
                        "salutation": null,
                        "title": "Chief Technology Officer",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T13:10:05.999Z",
                        "website_url": null,
                        "workflow_status": null
                      },
                      {
                        "about": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                        "bio": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                        "company": "Meridian Health",
                        "company_name": "Meridian Health",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "email": "daniel.okonkwo@example.com",
                        "firstName": "Daniel",
                        "first_name": "Daniel",
                        "friendly_id": "SPK-64947",
                        "friendly_id_raw": 64947,
                        "full_name": "Daniel Okonkwo",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                        "id": "m976sftaw9zr7fe2bnkcma60c58c9cmf",
                        "is_public": true,
                        "jobTitle": "Director of AI",
                        "lastName": "Okonkwo",
                        "last_name": "Okonkwo",
                        "linkedin_url": null,
                        "name": "Daniel Okonkwo",
                        "participant_role": {
                          "core_role": "speaker",
                          "name": "Speaker",
                          "name_plural": "Speakers",
                          "slug": "speaker"
                        },
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                        "pronouns": null,
                        "salutation": null,
                        "title": "Director of AI",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T13:10:05.999Z",
                        "website_url": null,
                        "workflow_status": null
                      }
                    ],
                    "startTime": 1791932400000,
                    "starts_at": "2026-10-13T23:00:00.000Z",
                    "status": "accepted",
                    "submittedAt": 1786453805999.9343,
                    "submitter": {
                      "about": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                      "bio": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                      "company": "Fathom Robotics",
                      "company_name": "Fathom Robotics",
                      "created_at": "2026-08-11T13:10:05.999Z",
                      "email": "noah.blackwood@example.com",
                      "firstName": "Noah",
                      "first_name": "Noah",
                      "friendly_id": "SPK-32294",
                      "friendly_id_raw": 32294,
                      "full_name": "Noah Blackwood",
                      "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                      "id": "m97ed5bzvtqddq1gm642p216js8c911f",
                      "is_public": true,
                      "jobTitle": "Chief Technology Officer",
                      "lastName": "Blackwood",
                      "last_name": "Blackwood",
                      "linkedin_url": null,
                      "name": "Noah Blackwood",
                      "participant_role": null,
                      "phone_mobile": null,
                      "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                      "pronouns": null,
                      "salutation": null,
                      "title": "Chief Technology Officer",
                      "twitter_url": null,
                      "updated_at": "2026-08-11T13:10:05.999Z",
                      "website_url": null,
                      "workflow_status": null
                    },
                    "subsessions": [],
                    "tags": [
                      {
                        "id": "panel",
                        "name": "panel"
                      },
                      {
                        "id": "agents",
                        "name": "agents"
                      }
                    ],
                    "title": "Closing panel: what we got wrong about agents",
                    "track": {
                      "color": "#1E9E6B",
                      "created_at": "2026-08-11T13:10:05.999Z",
                      "event_id": "j9722stesd2vbsdnppys47wqe98c8nb0",
                      "id": "kd77jbd8np4qh1xhz2xb85383s8c8c93",
                      "name": "Product",
                      "order": 1,
                      "updated_at": "2026-08-11T13:10:05.999Z"
                    },
                    "trackColor": "#1E9E6B",
                    "updated_at": "2026-08-11T13:10:05.999Z"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/sessions/bulk": {
      "post": {
        "operationId": "bulkSessions",
        "tags": [
          "Session Writes"
        ],
        "summary": "Bulk session operations",
        "description": "Up to 100 create/update/delete operations in one request. Each operation succeeds or fails independently and is reported by index, so a bad row never sinks the batch.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `session_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:sessions",
        "x-rate-limit-bucket": "session_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/BulkOperations"
              },
              "example": {
                "operations": [
                  {
                    "action": "create",
                    "data": {
                      "title": "Sponsor keynote",
                      "status": "accepted"
                    }
                  },
                  {
                    "action": "update",
                    "id": "k17abc…",
                    "data": {
                      "level": "Advanced"
                    }
                  },
                  {
                    "action": "delete",
                    "id": "k17def…"
                  }
                ]
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/BulkResponse"
                },
                "example": {
                  "batch_id": "batch_9f2c…",
                  "results": [
                    {
                      "index": 0,
                      "action": "create",
                      "status": "created",
                      "id": "k17ghi…"
                    },
                    {
                      "index": 1,
                      "action": "update",
                      "status": "updated",
                      "id": "k17abc…"
                    },
                    {
                      "index": 2,
                      "action": "delete",
                      "status": "failed",
                      "error": {
                        "code": "NotFoundError",
                        "message": "Session not found."
                      }
                    }
                  ],
                  "stats": {
                    "total": 3,
                    "succeeded": 2,
                    "failed": 1
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/sessions/create": {
      "post": {
        "operationId": "createSession",
        "tags": [
          "Session Writes"
        ],
        "summary": "Create a session",
        "description": "Creates a programme session, or an abstract when `is_abstract` is true. A submitter is resolved from `submitter_email` (created if new) and attached as the first speaker, so a session is never speakerless.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `session_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:sessions",
        "x-rate-limit-bucket": "session_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SessionWriteBody"
              },
              "example": {
                "title": "Designing agent workflows that survive contact with users",
                "description": "<p>What we learned shipping agents to 40k organizers.</p>",
                "status": "pending",
                "is_abstract": false,
                "format": "Talk",
                "level": "Intermediate",
                "language": "English",
                "tag_ids": [
                  "AI",
                  "Product"
                ],
                "starts_at": "2026-09-14T15:00:00.000Z",
                "ends_at": "2026-09-14T15:45:00.000Z",
                "submitter_email": "ada@example.com",
                "submitter_first_name": "Ada",
                "submitter_last_name": "Lovelace",
                "custom_fields": {
                  "takeaways": "Three patterns and one anti-pattern."
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionEnvelope"
                },
                "example": {
                  "data": {
                    "answers": {
                      "description": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today.",
                      "format": "Panel",
                      "language": "English",
                      "level": "Intermediate",
                      "takeaways": "Honest post-mortems from four production agent systems.",
                      "title": "Closing panel: what we got wrong about agents",
                      "track": "Product"
                    },
                    "capacity": 300,
                    "chairpersons": [],
                    "created_at": "2026-08-11T13:10:05.999Z",
                    "custom_fields": [
                      {
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "id": "description",
                        "internal_name": "description",
                        "name": "Session description",
                        "type": "long_text",
                        "value": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today.",
                        "value_raw": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today."
                      },
                      {
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "id": "format",
                        "internal_name": "format",
                        "name": "Format",
                        "type": "dropdown",
                        "value": "Panel",
                        "value_raw": "Panel"
                      }
                    ],
                    "decidedAt": 1785935405999,
                    "decided_at": "2026-08-05T13:10:05.999Z",
                    "deleted_at": null,
                    "description": "Four practitioners compare notes on the agent architectures they abandoned, the assumptions that did not survive production, and what they would build differently today.",
                    "durationMinutes": 60,
                    "duration_minutes": 60,
                    "endTime": 1791936000000,
                    "ends_at": "2026-10-14T00:00:00.000Z",
                    "format": {
                      "id": "Panel",
                      "name": "Panel"
                    },
                    "friendly_id": "SESS-42342",
                    "friendly_id_raw": 42342,
                    "id": "k57b5gt5pefy4jcjg6y6023yss8c9det",
                    "is_abstract": false,
                    "is_public": true,
                    "kind": "session",
                    "language": {
                      "id": "English",
                      "name": "English"
                    },
                    "level": {
                      "id": "Intermediate",
                      "name": "Intermediate"
                    },
                    "location": "Main Stage",
                    "moderators": [],
                    "notified_at": "2026-08-06T13:10:05.999Z",
                    "participants": [
                      {
                        "about": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "bio": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "company": "Fathom Robotics",
                        "company_name": "Fathom Robotics",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "email": "noah.blackwood@example.com",
                        "firstName": "Noah",
                        "first_name": "Noah",
                        "friendly_id": "SPK-32294",
                        "friendly_id_raw": 32294,
                        "full_name": "Noah Blackwood",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "id": "m97ed5bzvtqddq1gm642p216js8c911f",
                        "is_public": true,
                        "jobTitle": "Chief Technology Officer",
                        "lastName": "Blackwood",
                        "last_name": "Blackwood",
                        "linkedin_url": null,
                        "name": "Noah Blackwood",
                        "participant_role": {
                          "core_role": "speaker",
                          "name": "Speaker",
                          "name_plural": "Speakers",
                          "slug": "speaker"
                        },
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "pronouns": null,
                        "salutation": null,
                        "title": "Chief Technology Officer",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T13:10:05.999Z",
                        "website_url": null,
                        "workflow_status": null
                      },
                      {
                        "about": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                        "bio": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                        "company": "Meridian Health",
                        "company_name": "Meridian Health",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "email": "daniel.okonkwo@example.com",
                        "firstName": "Daniel",
                        "first_name": "Daniel",
                        "friendly_id": "SPK-64947",
                        "friendly_id_raw": 64947,
                        "full_name": "Daniel Okonkwo",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                        "id": "m976sftaw9zr7fe2bnkcma60c58c9cmf",
                        "is_public": true,
                        "jobTitle": "Director of AI",
                        "lastName": "Okonkwo",
                        "last_name": "Okonkwo",
                        "linkedin_url": null,
                        "name": "Daniel Okonkwo",
                        "participant_role": {
                          "core_role": "speaker",
                          "name": "Speaker",
                          "name_plural": "Speakers",
                          "slug": "speaker"
                        },
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                        "pronouns": null,
                        "salutation": null,
                        "title": "Director of AI",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T13:10:05.999Z",
                        "website_url": null,
                        "workflow_status": null
                      }
                    ],
                    "public_visible": true,
                    "room": {
                      "capacity": 300,
                      "created_at": "2026-08-11T13:10:05.999Z",
                      "id": "js76t15v2t5z854w4ct9t46gxh8c8aac",
                      "name": "Main Stage",
                      "order": 0,
                      "updated_at": "2026-08-11T13:10:05.999Z"
                    },
                    "speakers": [
                      {
                        "about": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "bio": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                        "company": "Fathom Robotics",
                        "company_name": "Fathom Robotics",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "email": "noah.blackwood@example.com",
                        "firstName": "Noah",
                        "first_name": "Noah",
                        "friendly_id": "SPK-32294",
                        "friendly_id_raw": 32294,
                        "full_name": "Noah Blackwood",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "id": "m97ed5bzvtqddq1gm642p216js8c911f",
                        "is_public": true,
                        "jobTitle": "Chief Technology Officer",
                        "lastName": "Blackwood",
                        "last_name": "Blackwood",
                        "linkedin_url": null,
                        "name": "Noah Blackwood",
                        "participant_role": {
                          "core_role": "speaker",
                          "name": "Speaker",
                          "name_plural": "Speakers",
                          "slug": "speaker"
                        },
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                        "pronouns": null,
                        "salutation": null,
                        "title": "Chief Technology Officer",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T13:10:05.999Z",
                        "website_url": null,
                        "workflow_status": null
                      },
                      {
                        "about": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                        "bio": "Daniel builds clinical decision-support systems at Meridian Health, in a regulatory environment where 'we will fix it in the next deploy' is not an option.",
                        "company": "Meridian Health",
                        "company_name": "Meridian Health",
                        "created_at": "2026-08-11T13:10:05.999Z",
                        "email": "daniel.okonkwo@example.com",
                        "firstName": "Daniel",
                        "first_name": "Daniel",
                        "friendly_id": "SPK-64947",
                        "friendly_id_raw": 64947,
                        "full_name": "Daniel Okonkwo",
                        "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                        "id": "m976sftaw9zr7fe2bnkcma60c58c9cmf",
                        "is_public": true,
                        "jobTitle": "Director of AI",
                        "lastName": "Okonkwo",
                        "last_name": "Okonkwo",
                        "linkedin_url": null,
                        "name": "Daniel Okonkwo",
                        "participant_role": {
                          "core_role": "speaker",
                          "name": "Speaker",
                          "name_plural": "Speakers",
                          "slug": "speaker"
                        },
                        "phone_mobile": null,
                        "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/61467429-9683-43c8-af19-cf519d3e2653",
                        "pronouns": null,
                        "salutation": null,
                        "title": "Director of AI",
                        "twitter_url": null,
                        "updated_at": "2026-08-11T13:10:05.999Z",
                        "website_url": null,
                        "workflow_status": null
                      }
                    ],
                    "startTime": 1791932400000,
                    "starts_at": "2026-10-13T23:00:00.000Z",
                    "status": "accepted",
                    "submittedAt": 1786453805999.9343,
                    "submitter": {
                      "about": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                      "bio": "Noah is CTO at Fathom Robotics, where inference cost is a line item the board reads every month. He previously built pricing systems at a payments company.",
                      "company": "Fathom Robotics",
                      "company_name": "Fathom Robotics",
                      "created_at": "2026-08-11T13:10:05.999Z",
                      "email": "noah.blackwood@example.com",
                      "firstName": "Noah",
                      "first_name": "Noah",
                      "friendly_id": "SPK-32294",
                      "friendly_id_raw": 32294,
                      "full_name": "Noah Blackwood",
                      "headshotUrl": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                      "id": "m97ed5bzvtqddq1gm642p216js8c911f",
                      "is_public": true,
                      "jobTitle": "Chief Technology Officer",
                      "lastName": "Blackwood",
                      "last_name": "Blackwood",
                      "linkedin_url": null,
                      "name": "Noah Blackwood",
                      "participant_role": null,
                      "phone_mobile": null,
                      "photo_url": "https://neat-sparrow-926.eu-west-1.convex.cloud/api/storage/6deb820b-9fba-44e5-9367-620e8f476663",
                      "pronouns": null,
                      "salutation": null,
                      "title": "Chief Technology Officer",
                      "twitter_url": null,
                      "updated_at": "2026-08-11T13:10:05.999Z",
                      "website_url": null,
                      "workflow_status": null
                    },
                    "subsessions": [],
                    "tags": [
                      {
                        "id": "panel",
                        "name": "panel"
                      },
                      {
                        "id": "agents",
                        "name": "agents"
                      }
                    ],
                    "title": "Closing panel: what we got wrong about agents",
                    "track": {
                      "color": "#1E9E6B",
                      "created_at": "2026-08-11T13:10:05.999Z",
                      "event_id": "j9722stesd2vbsdnppys47wqe98c8nb0",
                      "id": "kd77jbd8np4qh1xhz2xb85383s8c8c93",
                      "name": "Product",
                      "order": 1,
                      "updated_at": "2026-08-11T13:10:05.999Z"
                    },
                    "trackColor": "#1E9E6B",
                    "updated_at": "2026-08-11T13:10:05.999Z"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/sessions/status": {
      "post": {
        "operationId": "searchSessionsByStatus",
        "tags": [
          "Sessions"
        ],
        "summary": "Search sessions by status",
        "description": "Lightweight id + status projection with no joins — the cheap way to reconcile a mirror. Soft-deleted rows are included, carrying `deleted_at`.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.",
        "x-required-scope": "read:sessions",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SessionSearchBody"
              },
              "example": {
                "filters": {
                  "updatedAt": {
                    "after": "2026-08-01T00:00:00.000Z"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SessionStatusesPage"
                },
                "example": {
                  "data": [
                    {
                      "id": "k17abc…",
                      "friendly_id": "SESS-73041",
                      "friendly_id_raw": 73041,
                      "status": "accepted",
                      "is_abstract": false,
                      "deleted_at": null,
                      "created_at": "2026-06-02T11:03:12.884Z",
                      "updated_at": "2026-08-11T09:12:44.001Z",
                      "subsessions": []
                    }
                  ],
                  "results": [
                    {
                      "id": "k17abc…",
                      "friendly_id": "SESS-73041",
                      "friendly_id_raw": 73041,
                      "status": "accepted",
                      "is_abstract": false,
                      "deleted_at": null,
                      "created_at": "2026-06-02T11:03:12.884Z",
                      "updated_at": "2026-08-11T09:12:44.001Z",
                      "subsessions": []
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "pageSize": 25,
                    "totalPages": 1,
                    "totalResults": 1,
                    "current_page": 1,
                    "page_size": 25,
                    "total_pages": 1,
                    "total_results": 1
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/speakers": {
      "get": {
        "operationId": "listSpeakers",
        "tags": [
          "Speakers"
        ],
        "summary": "List speakers",
        "description": "Everyone on the event's roster with the sessions they are on, ordered by surname.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:contacts` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.",
        "x-required-scope": "read:contacts",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          },
          {
            "$ref": "#/components/parameters/search"
          },
          {
            "$ref": "#/components/parameters/workflow_status"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SpeakersPage"
                },
                "example": {
                  "data": [
                    {
                      "about": "Organizer-written bio for the public page.",
                      "bio": "Organizer-written bio for the public page.",
                      "company": "Keynote Co",
                      "company_name": "Keynote Co",
                      "created_at": "2026-08-11T19:29:07.551Z",
                      "email": "manual-speaker-msp20e3l@example.com",
                      "firstName": "Manu",
                      "first_name": "Manu",
                      "friendly_id": "SPK-43535",
                      "friendly_id_raw": 43535,
                      "full_name": "Manu Alvarez",
                      "headshotUrl": null,
                      "id": "m97bwdch4tfk32vnzsyj3kh41h8c8662",
                      "is_public": true,
                      "jobTitle": "CTO",
                      "lastName": "Alvarez",
                      "last_name": "Alvarez",
                      "linkedin_url": null,
                      "name": "Manu Alvarez",
                      "participant_role": null,
                      "phone_mobile": null,
                      "photo_url": null,
                      "pronouns": null,
                      "salutation": null,
                      "sessions": [],
                      "title": "CTO",
                      "twitter_url": null,
                      "updated_at": "2026-08-11T19:29:09.915Z",
                      "website_url": null,
                      "workflow_status": "confirmed"
                    }
                  ],
                  "event": {
                    "_id": "j976eyym787qhaq02v0nea4k7x8c879q",
                    "agenda_published_at": "2026-08-06T19:27:45.331Z",
                    "background_url": null,
                    "created_at": "2026-08-11T19:27:45.331Z",
                    "description": "Two days for the people building AI systems that have to work on Monday morning. Practitioner talks on evaluation, agents, retrieval, inference infrastructure and the product decisions in between — no keynote fluff, no vendor pitches.",
                    "endsAt": 1791939600000,
                    "ends_at": "2026-10-14T01:00:00.000Z",
                    "features": {
                      "custom_fields": true,
                      "translated_fields": false,
                      "webhooks": true
                    },
                    "id": "j976eyym787qhaq02v0nea4k7x8c879q",
                    "logo_url": null,
                    "name": "AI Engineer Summit 2026",
                    "organization_id": "mn7fs8btg5szyhbkqdfhtd4xmn8c8xhg",
                    "portal_settings": {
                      "allow_submission_edits": true,
                      "always_show_tasks": false,
                      "extend_task_deadlines": true
                    },
                    "public_url": "/e/ai-engineer/ai-summit-2026",
                    "slug": "ai-summit-2026",
                    "startsAt": 1791820800000,
                    "starts_at": "2026-10-12T16:00:00.000Z",
                    "timezone": "America/Los_Angeles",
                    "type": "Conference",
                    "venue": "Moscone West, San Francisco",
                    "websiteUrl": "https://example.com/ai-summit-2026",
                    "website_url": "https://example.com/ai-summit-2026"
                  },
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 1,
                    "page_size": 1,
                    "totalPages": 19,
                    "totalResults": 19,
                    "total_pages": 19,
                    "total_results": 19
                  },
                  "results": [
                    {
                      "about": "Organizer-written bio for the public page.",
                      "bio": "Organizer-written bio for the public page.",
                      "company": "Keynote Co",
                      "company_name": "Keynote Co",
                      "created_at": "2026-08-11T19:29:07.551Z",
                      "email": "manual-speaker-msp20e3l@example.com",
                      "firstName": "Manu",
                      "first_name": "Manu",
                      "friendly_id": "SPK-43535",
                      "friendly_id_raw": 43535,
                      "full_name": "Manu Alvarez",
                      "headshotUrl": null,
                      "id": "m97bwdch4tfk32vnzsyj3kh41h8c8662",
                      "is_public": true,
                      "jobTitle": "CTO",
                      "lastName": "Alvarez",
                      "last_name": "Alvarez",
                      "linkedin_url": null,
                      "name": "Manu Alvarez",
                      "participant_role": null,
                      "phone_mobile": null,
                      "photo_url": null,
                      "pronouns": null,
                      "salutation": null,
                      "sessions": [],
                      "title": "CTO",
                      "twitter_url": null,
                      "updated_at": "2026-08-11T19:29:09.915Z",
                      "website_url": null,
                      "workflow_status": "confirmed"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "post": {
        "operationId": "searchSpeakers",
        "tags": [
          "Speakers"
        ],
        "summary": "Search speakers",
        "description": "Same data as the list form, with the search body Sessionboard clients send.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:contacts` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.",
        "x-required-scope": "read:contacts",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SpeakerSearchBody"
              },
              "example": {
                "filters": {
                  "search": "hopper",
                  "workflowStatus": "confirmed"
                },
                "sort": {
                  "sort": "asc"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SpeakersPage"
                },
                "example": {
                  "data": [
                    {
                      "about": null,
                      "bio": null,
                      "company": null,
                      "company_name": null,
                      "created_at": "2026-08-11T13:10:49.206Z",
                      "email": "maya.chen@example.com",
                      "firstName": "",
                      "first_name": "",
                      "friendly_id": "SPK-89967",
                      "friendly_id_raw": 89967,
                      "full_name": "Speaker",
                      "headshotUrl": null,
                      "id": "m9770ghdp26afae2ne8p777kpd8c84qn",
                      "is_public": true,
                      "jobTitle": null,
                      "lastName": "",
                      "last_name": "",
                      "linkedin_url": null,
                      "name": "Speaker",
                      "participant_role": null,
                      "phone_mobile": null,
                      "photo_url": null,
                      "pronouns": null,
                      "salutation": null,
                      "sessions": [],
                      "title": null,
                      "twitter_url": null,
                      "updated_at": "2026-08-11T13:10:49.206Z",
                      "website_url": null,
                      "workflow_status": null
                    }
                  ],
                  "event": {
                    "_id": "j9722stesd2vbsdnppys47wqe98c8nb0",
                    "agenda_published_at": "2026-08-06T13:10:05.999Z",
                    "background_url": null,
                    "created_at": "2026-08-11T13:10:05.999Z",
                    "description": "Two days for the people building AI systems that have to work on Monday morning. Practitioner talks on evaluation, agents, retrieval, inference infrastructure and the product decisions in between — no keynote fluff, no vendor pitches.",
                    "endsAt": 1791939600000,
                    "ends_at": "2026-10-14T01:00:00.000Z",
                    "features": {
                      "custom_fields": true,
                      "translated_fields": false,
                      "webhooks": true
                    },
                    "id": "j9722stesd2vbsdnppys47wqe98c8nb0",
                    "logo_url": null,
                    "name": "AI Engineer Summit 2026",
                    "organization_id": "mn7fs8btg5szyhbkqdfhtd4xmn8c8xhg",
                    "portal_settings": {
                      "allow_submission_edits": true,
                      "always_show_tasks": false,
                      "extend_task_deadlines": true
                    },
                    "public_url": "/e/ai-summit-2026",
                    "slug": "ai-summit-2026",
                    "startsAt": 1791820800000,
                    "starts_at": "2026-10-12T16:00:00.000Z",
                    "timezone": "America/Los_Angeles",
                    "type": "Conference",
                    "venue": "Moscone West, San Francisco",
                    "websiteUrl": "https://example.com/ai-summit-2026",
                    "website_url": "https://example.com/ai-summit-2026"
                  },
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 1,
                    "page_size": 1,
                    "totalPages": 15,
                    "totalResults": 15,
                    "total_pages": 15,
                    "total_results": 15
                  },
                  "results": [
                    {
                      "about": null,
                      "bio": null,
                      "company": null,
                      "company_name": null,
                      "created_at": "2026-08-11T13:10:49.206Z",
                      "email": "maya.chen@example.com",
                      "firstName": "",
                      "first_name": "",
                      "friendly_id": "SPK-89967",
                      "friendly_id_raw": 89967,
                      "full_name": "Speaker",
                      "headshotUrl": null,
                      "id": "m9770ghdp26afae2ne8p777kpd8c84qn",
                      "is_public": true,
                      "jobTitle": null,
                      "lastName": "",
                      "last_name": "",
                      "linkedin_url": null,
                      "name": "Speaker",
                      "participant_role": null,
                      "phone_mobile": null,
                      "photo_url": null,
                      "pronouns": null,
                      "salutation": null,
                      "sessions": [],
                      "title": null,
                      "twitter_url": null,
                      "updated_at": "2026-08-11T13:10:49.206Z",
                      "website_url": null,
                      "workflow_status": null
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/speakers/{speakerId}": {
      "get": {
        "operationId": "getSpeaker",
        "tags": [
          "Speakers"
        ],
        "summary": "Get a speaker",
        "description": "One speaker with every session they participate in, in full session shape.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:contacts` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:contacts",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/speakerId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SpeakerEnvelope"
                },
                "example": {
                  "data": {
                    "about": null,
                    "bio": null,
                    "company": null,
                    "company_name": null,
                    "created_at": "2026-08-11T13:10:49.206Z",
                    "email": "maya.chen@example.com",
                    "firstName": "",
                    "first_name": "",
                    "friendly_id": "SPK-89967",
                    "friendly_id_raw": 89967,
                    "full_name": "Speaker",
                    "headshotUrl": null,
                    "id": "m9770ghdp26afae2ne8p777kpd8c84qn",
                    "is_public": true,
                    "jobTitle": null,
                    "lastName": "",
                    "last_name": "",
                    "linkedin_url": null,
                    "name": "Speaker",
                    "participant_role": null,
                    "phone_mobile": null,
                    "photo_url": null,
                    "pronouns": null,
                    "salutation": null,
                    "sessions": [],
                    "title": null,
                    "twitter_url": null,
                    "updated_at": "2026-08-11T13:10:49.206Z",
                    "website_url": null,
                    "workflow_status": null
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "put": {
        "operationId": "updateSpeaker",
        "tags": [
          "Speakers"
        ],
        "summary": "Update a speaker",
        "description": "Partial update of a speaker's profile and workflow status.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:contacts` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `session_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:contacts",
        "x-rate-limit-bucket": "session_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/speakerId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SpeakerWriteBody"
              },
              "example": {
                "workflow_status": "confirmed",
                "is_public": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SpeakerEnvelope"
                },
                "example": {
                  "data": {
                    "about": null,
                    "bio": null,
                    "company": null,
                    "company_name": null,
                    "created_at": "2026-08-11T13:10:49.206Z",
                    "email": "maya.chen@example.com",
                    "firstName": "",
                    "first_name": "",
                    "friendly_id": "SPK-89967",
                    "friendly_id_raw": 89967,
                    "full_name": "Speaker",
                    "headshotUrl": null,
                    "id": "m9770ghdp26afae2ne8p777kpd8c84qn",
                    "is_public": true,
                    "jobTitle": null,
                    "lastName": "",
                    "last_name": "",
                    "linkedin_url": null,
                    "name": "Speaker",
                    "participant_role": null,
                    "phone_mobile": null,
                    "photo_url": null,
                    "pronouns": null,
                    "salutation": null,
                    "sessions": [],
                    "title": null,
                    "twitter_url": null,
                    "updated_at": "2026-08-11T13:10:49.206Z",
                    "website_url": null,
                    "workflow_status": null
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "delete": {
        "operationId": "deleteSpeaker",
        "tags": [
          "Speakers"
        ],
        "summary": "Remove a speaker from the roster",
        "description": "Deletes the person, their tasks and their uploaded files (blobs included). Refused with a 400 while they are still the submitter or a participant on any live session — detach them there first, so this can never silently orphan a talk that is still in the pipeline.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:contacts` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `session_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:contacts",
        "x-rate-limit-bucket": "session_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/speakerId"
          }
        ],
        "responses": {
          "204": {
            "description": "No content.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/speakers/create": {
      "post": {
        "operationId": "createSpeaker",
        "tags": [
          "Speakers"
        ],
        "summary": "Create a speaker",
        "description": "Adds someone to the roster. Idempotent on email within the event: creating a speaker who already exists updates their workflow status instead of duplicating them.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:contacts` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `session_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:contacts",
        "x-rate-limit-bucket": "session_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SpeakerWriteBody"
              },
              "example": {
                "email": "grace@example.com",
                "first_name": "Grace",
                "last_name": "Hopper",
                "title": "Distinguished Engineer",
                "company_name": "Example Corp",
                "about": "Compilers, and why they matter.",
                "workflow_status": "invited"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SpeakerEnvelope"
                },
                "example": {
                  "data": {
                    "about": null,
                    "bio": null,
                    "company": null,
                    "company_name": null,
                    "created_at": "2026-08-11T13:10:49.206Z",
                    "email": "maya.chen@example.com",
                    "firstName": "",
                    "first_name": "",
                    "friendly_id": "SPK-89967",
                    "friendly_id_raw": 89967,
                    "full_name": "Speaker",
                    "headshotUrl": null,
                    "id": "m9770ghdp26afae2ne8p777kpd8c84qn",
                    "is_public": true,
                    "jobTitle": null,
                    "lastName": "",
                    "last_name": "",
                    "linkedin_url": null,
                    "name": "Speaker",
                    "participant_role": null,
                    "phone_mobile": null,
                    "photo_url": null,
                    "pronouns": null,
                    "salutation": null,
                    "sessions": [],
                    "title": null,
                    "twitter_url": null,
                    "updated_at": "2026-08-11T13:10:49.206Z",
                    "website_url": null,
                    "workflow_status": null
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/statuses": {
      "get": {
        "operationId": "listStatuses",
        "tags": [
          "Event Settings"
        ],
        "summary": "List statuses",
        "description": "Every status a session can be in: the seven built-ins every event ships with, plus any custom labels this event added. `id` is the pipeline value for a built-in and the row id for a custom status; `pipeline_status` is always the value `?status=` filters on. Pass `include_deleted=true` to see archived ones.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          },
          {
            "$ref": "#/components/parameters/search"
          },
          {
            "$ref": "#/components/parameters/include_deleted"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatusesPage"
                },
                "example": {
                  "data": [
                    {
                      "category": "accepted",
                      "color": "green",
                      "created_at": null,
                      "created_by": null,
                      "deleted_at": null,
                      "id": "accepted",
                      "name": "Accepted",
                      "order": 10,
                      "pipeline_status": "accepted",
                      "status_id": "p57fb2kbg09t1khn58fdtjyqc18c9pnm",
                      "system": true,
                      "system_key": "accepted",
                      "updated_at": null,
                      "value": "accepted"
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 25,
                    "page_size": 25,
                    "totalPages": 1,
                    "totalResults": 8,
                    "total_pages": 1,
                    "total_results": 8
                  },
                  "results": [
                    {
                      "category": "accepted",
                      "color": "green",
                      "created_at": null,
                      "created_by": null,
                      "deleted_at": null,
                      "id": "accepted",
                      "name": "Accepted",
                      "order": 10,
                      "pipeline_status": "accepted",
                      "status_id": "p57fb2kbg09t1khn58fdtjyqc18c9pnm",
                      "system": true,
                      "system_key": "accepted",
                      "updated_at": null,
                      "value": "accepted"
                    }
                  ],
                  "unknownResource": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "post": {
        "operationId": "searchStatuses",
        "tags": [
          "Event Settings"
        ],
        "summary": "Search statuses",
        "description": "Same data as the list form, with the search body Sessionboard clients send.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataSearchBody"
              },
              "example": {
                "filters": {
                  "search": "accept"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatusesPage"
                },
                "example": {
                  "data": [
                    {
                      "category": "accepted",
                      "color": "green",
                      "created_at": null,
                      "created_by": null,
                      "deleted_at": null,
                      "id": "accepted",
                      "name": "Accepted",
                      "order": 10,
                      "pipeline_status": "accepted",
                      "status_id": "p573r4hrnkaa658391v76a7q358c8fcq",
                      "system": true,
                      "system_key": "accepted",
                      "updated_at": null,
                      "value": "accepted"
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 25,
                    "page_size": 25,
                    "totalPages": 1,
                    "totalResults": 8,
                    "total_pages": 1,
                    "total_results": 8
                  },
                  "results": [
                    {
                      "category": "accepted",
                      "color": "green",
                      "created_at": null,
                      "created_by": null,
                      "deleted_at": null,
                      "id": "accepted",
                      "name": "Accepted",
                      "order": 10,
                      "pipeline_status": "accepted",
                      "status_id": "p573r4hrnkaa658391v76a7q358c8fcq",
                      "system": true,
                      "system_key": "accepted",
                      "updated_at": null,
                      "value": "accepted"
                    }
                  ],
                  "unknownResource": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/statuses/{id}": {
      "put": {
        "operationId": "updateStatuse",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Update a session status",
        "description": "Renames or reorders a session status. A custom status is a LABEL bound to one of the five pipeline categories (`category`), so “Waitlist” can be the word an organizer sees while the accept/decline machinery, the decision emails and the speaker portal all keep running on `pending`. The seven built-ins can be renamed, recoloured and reordered but never deleted or re-categorised.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataWriteBody"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatusEnvelope"
                },
                "example": {
                  "data": {
                    "category": "accepted",
                    "color": "green",
                    "created_at": null,
                    "created_by": null,
                    "deleted_at": null,
                    "id": "accepted",
                    "name": "Accepted",
                    "order": 10,
                    "pipeline_status": "accepted",
                    "status_id": "p573r4hrnkaa658391v76a7q358c8fcq",
                    "system": true,
                    "system_key": "accepted",
                    "updated_at": null,
                    "value": "accepted"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "delete": {
        "operationId": "deleteStatuse",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Delete a session status",
        "description": "Archives a custom status — soft, so `POST /statuses/{id}/restore` brings it back. Submissions still carrying the label must be sent somewhere with `reassign_to`, or the call answers 400 with how many. Built-in statuses refuse deletion.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "requestBody": {
          "required": false,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataWriteBody"
              }
            }
          }
        },
        "responses": {
          "204": {
            "description": "No content.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/statuses/{id}/restore": {
      "post": {
        "operationId": "restoreStatus",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Restore a deleted session status",
        "description": "Undoes a `DELETE /statuses/{id}`. Deleting a custom status archives it rather than destroying it, so a mis-click is one call away from being undone. Restoring answers 400 if a live status has since taken the same name.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatusEnvelope"
                },
                "example": {
                  "data": {
                    "category": "accepted",
                    "color": "green",
                    "created_at": null,
                    "created_by": null,
                    "deleted_at": null,
                    "id": "accepted",
                    "name": "Accepted",
                    "order": 10,
                    "pipeline_status": "accepted",
                    "status_id": "p573r4hrnkaa658391v76a7q358c8fcq",
                    "system": true,
                    "system_key": "accepted",
                    "updated_at": null,
                    "value": "accepted"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/statuses/create": {
      "post": {
        "operationId": "createStatuse",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Create a session status",
        "description": "Adds a session status to the event. A custom status is a LABEL bound to one of the five pipeline categories (`category`), so “Waitlist” can be the word an organizer sees while the accept/decline machinery, the decision emails and the speaker portal all keep running on `pending`. The seven built-ins can be renamed, recoloured and reordered but never deleted or re-categorised.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataWriteBody"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/StatusEnvelope"
                },
                "example": {
                  "data": {
                    "category": "accepted",
                    "color": "green",
                    "created_at": null,
                    "created_by": null,
                    "deleted_at": null,
                    "id": "accepted",
                    "name": "Accepted",
                    "order": 10,
                    "pipeline_status": "accepted",
                    "status_id": "p573r4hrnkaa658391v76a7q358c8fcq",
                    "system": true,
                    "system_key": "accepted",
                    "updated_at": null,
                    "value": "accepted"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/submissions": {
      "get": {
        "operationId": "listSubmissions",
        "tags": [
          "Sessions"
        ],
        "summary": "List submissions",
        "description": "Every submission for the event with its participants, in the shape this endpoint has returned since before the parity work. `POST /sessions` with `filters.isAbstract` is the richer modern equivalent.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:sessions` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.",
        "x-required-scope": "read:sessions",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/SubmissionsPage"
                },
                "example": {
                  "data": [
                    {
                      "decidedAt": null,
                      "description": "<p>A talk created by the verify script.</p>",
                      "format": "Talk",
                      "id": "k57ckgh8zj62bw9ayph9c9vb758c8vqx",
                      "kind": "abstract",
                      "language": "English",
                      "level": "Introductory",
                      "speakers": [
                        {
                          "company": null,
                          "email": "verify-quiet-msp1ytiv@example.com",
                          "id": "m97fky4rwn7cfknckagxepcpdx8c8wff",
                          "jobTitle": null,
                          "name": "Quinn Quiet",
                          "role": "speaker"
                        }
                      ],
                      "status": "pending",
                      "submittedAt": 1786476474498.164,
                      "tags": [],
                      "title": "Quiet Talk",
                      "track": "AI Engineering"
                    }
                  ],
                  "event": {
                    "_id": "j976eyym787qhaq02v0nea4k7x8c879q",
                    "endsAt": 1791939600000,
                    "name": "AI Engineer Summit 2026",
                    "slug": "ai-summit-2026",
                    "startsAt": 1791820800000,
                    "timezone": "America/Los_Angeles",
                    "venue": "Moscone West, San Francisco"
                  },
                  "pagination": {
                    "currentPage": 1,
                    "pageSize": 1,
                    "totalPages": 20,
                    "totalResults": 20
                  },
                  "results": [
                    {
                      "decidedAt": null,
                      "description": "<p>A talk created by the verify script.</p>",
                      "format": "Talk",
                      "id": "k57ckgh8zj62bw9ayph9c9vb758c8vqx",
                      "kind": "abstract",
                      "language": "English",
                      "level": "Introductory",
                      "speakers": [
                        {
                          "company": null,
                          "email": "verify-quiet-msp1ytiv@example.com",
                          "id": "m97fky4rwn7cfknckagxepcpdx8c8wff",
                          "jobTitle": null,
                          "name": "Quinn Quiet",
                          "role": "speaker"
                        }
                      ],
                      "status": "pending",
                      "submittedAt": 1786476474498.164,
                      "tags": [],
                      "title": "Quiet Talk",
                      "track": "AI Engineering"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/tags": {
      "get": {
        "operationId": "listTags",
        "tags": [
          "Event Settings"
        ],
        "summary": "List tags",
        "description": "Every tag configured on the event.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          },
          {
            "$ref": "#/components/parameters/search"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataPage"
                },
                "example": {
                  "data": [
                    {
                      "created_at": null,
                      "id": "adoption",
                      "name": "adoption",
                      "order": 0,
                      "updated_at": null
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 25,
                    "page_size": 25,
                    "totalPages": 2,
                    "totalResults": 30,
                    "total_pages": 2,
                    "total_results": 30
                  },
                  "results": [
                    {
                      "created_at": null,
                      "id": "adoption",
                      "name": "adoption",
                      "order": 0,
                      "updated_at": null
                    }
                  ],
                  "unknownResource": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "post": {
        "operationId": "searchTags",
        "tags": [
          "Event Settings"
        ],
        "summary": "Search tags",
        "description": "Same data as the list form, with the search body Sessionboard clients send.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataSearchBody"
              },
              "example": {
                "filters": {
                  "search": "open"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataPage"
                },
                "example": {
                  "data": [
                    {
                      "created_at": null,
                      "id": "adoption",
                      "name": "adoption",
                      "order": 0,
                      "updated_at": null
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 25,
                    "page_size": 25,
                    "totalPages": 2,
                    "totalResults": 30,
                    "total_pages": 2,
                    "total_results": 30
                  },
                  "results": [
                    {
                      "created_at": null,
                      "id": "adoption",
                      "name": "adoption",
                      "order": 0,
                      "updated_at": null
                    }
                  ],
                  "unknownResource": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/tags/{id}": {
      "put": {
        "operationId": "updateTag",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Update a tag",
        "description": "Renames or reorders a tag. Tags have no table of their own: they are the options on the CFP form's `tags` question, so this edits that question and the form builder shows the change immediately.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataWriteBody"
              },
              "example": {
                "name": "Open source"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataEnvelope"
                },
                "example": {
                  "data": {
                    "created_at": null,
                    "id": "adoption",
                    "name": "adoption",
                    "order": 0,
                    "updated_at": null
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "delete": {
        "operationId": "deleteTag",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Delete a tag",
        "description": "Removes the tag. Tags have no table of their own: they are the options on the CFP form's `tags` question, so this edits that question and the form builder shows the change immediately.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "responses": {
          "204": {
            "description": "No content.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/tags/create": {
      "post": {
        "operationId": "createTag",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Create a tag",
        "description": "Adds a tag to the event. Tags have no table of their own: they are the options on the CFP form's `tags` question, so this edits that question and the form builder shows the change immediately.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataWriteBody"
              },
              "example": {
                "name": "Open Source"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataEnvelope"
                },
                "example": {
                  "data": {
                    "created_at": null,
                    "id": "adoption",
                    "name": "adoption",
                    "order": 0,
                    "updated_at": null
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/tasks": {
      "get": {
        "operationId": "listTasks",
        "tags": [
          "Tasks"
        ],
        "summary": "List speaker tasks",
        "description": "Every onboarding and deliverable task on the event. `?status=open|completed|overdue` is the outstanding-tasks dashboard as an API call; filter further by `speaker_id` or `session_id`.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.",
        "x-required-scope": "read:events",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          },
          {
            "$ref": "#/components/parameters/status"
          },
          {
            "$ref": "#/components/parameters/speaker_id"
          },
          {
            "$ref": "#/components/parameters/session_id"
          },
          {
            "$ref": "#/components/parameters/search"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TasksPage"
                },
                "example": {
                  "data": [
                    {
                      "completed_at": null,
                      "created_at": "2026-08-11T19:28:45.611Z",
                      "due_at": "2026-08-18T19:28:45.487Z",
                      "form_id": null,
                      "id": "k9749dbr22jwd5x0e287zj4c2s8c8219",
                      "instructions": "Hi {{firstName}} — please upload the deck for “{{sessionTitle}}” as a PDF, 16:9. We collect slides a week ahead so the AV team can test them on the room projectors.",
                      "is_complete": false,
                      "is_overdue": false,
                      "kind": "upload",
                      "response": null,
                      "session_id": null,
                      "session_title": null,
                      "speaker": {
                        "email": "verify-e2e-msp1yrr9@example.com",
                        "full_name": "Vera Efftest",
                        "id": "m975yb2bcxrwfxc33qzmd8pthh8c8pwg"
                      },
                      "speaker_id": "m975yb2bcxrwfxc33qzmd8pthh8c8pwg",
                      "title": "Upload your slides"
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 1,
                    "page_size": 1,
                    "totalPages": 28,
                    "totalResults": 28,
                    "total_pages": 28,
                    "total_results": 28
                  },
                  "results": [
                    {
                      "completed_at": null,
                      "created_at": "2026-08-11T19:28:45.611Z",
                      "due_at": "2026-08-18T19:28:45.487Z",
                      "form_id": null,
                      "id": "k9749dbr22jwd5x0e287zj4c2s8c8219",
                      "instructions": "Hi {{firstName}} — please upload the deck for “{{sessionTitle}}” as a PDF, 16:9. We collect slides a week ahead so the AV team can test them on the room projectors.",
                      "is_complete": false,
                      "is_overdue": false,
                      "kind": "upload",
                      "response": null,
                      "session_id": null,
                      "session_title": null,
                      "speaker": {
                        "email": "verify-e2e-msp1yrr9@example.com",
                        "full_name": "Vera Efftest",
                        "id": "m975yb2bcxrwfxc33qzmd8pthh8c8pwg"
                      },
                      "speaker_id": "m975yb2bcxrwfxc33qzmd8pthh8c8pwg",
                      "title": "Upload your slides"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/tasks/{taskId}": {
      "get": {
        "operationId": "getTask",
        "tags": [
          "Tasks"
        ],
        "summary": "Get a task",
        "description": "One task with the speaker it belongs to and the session it is about.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/taskId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskEnvelope"
                },
                "example": {
                  "data": {
                    "completed_at": null,
                    "created_at": "2026-08-11T19:28:45.611Z",
                    "due_at": "2026-08-18T19:28:45.487Z",
                    "form_id": null,
                    "id": "k9749dbr22jwd5x0e287zj4c2s8c8219",
                    "instructions": "Hi {{firstName}} — please upload the deck for “{{sessionTitle}}” as a PDF, 16:9. We collect slides a week ahead so the AV team can test them on the room projectors.",
                    "is_complete": false,
                    "is_overdue": false,
                    "kind": "upload",
                    "response": null,
                    "session_id": null,
                    "session_title": null,
                    "speaker": {
                      "email": "verify-e2e-msp1yrr9@example.com",
                      "full_name": "Vera Efftest",
                      "id": "m975yb2bcxrwfxc33qzmd8pthh8c8pwg"
                    },
                    "speaker_id": "m975yb2bcxrwfxc33qzmd8pthh8c8pwg",
                    "title": "Upload your slides"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "put": {
        "operationId": "updateTask",
        "tags": [
          "Tasks"
        ],
        "summary": "Update a task",
        "description": "Change the wording, the kind or the due date — or send `completed: true` to tick it off on the speaker's behalf (and `false` to reopen it).\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `event_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:events",
        "x-rate-limit-bucket": "event_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/taskId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TaskWriteBody"
              },
              "example": {
                "due_at": "2026-09-05T17:00:00.000Z",
                "completed": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskEnvelope"
                },
                "example": {
                  "data": {
                    "completed_at": null,
                    "created_at": "2026-08-11T13:10:05.999Z",
                    "due_at": "2026-08-31T13:10:05.999Z",
                    "form_id": null,
                    "id": "k970y3kmg1exvwn7r70kkghp4h8c9dz1",
                    "instructions": "PDF please, 16:9. We collect slides a week ahead so the AV team can test them.",
                    "is_complete": false,
                    "is_overdue": false,
                    "kind": "upload",
                    "session_id": null,
                    "session_title": null,
                    "speaker": {
                      "email": "rafael.duarte@example.com",
                      "full_name": "Rafael Duarte",
                      "id": "m970n6z2cax863gzfh75c1rqq98c8kxg"
                    },
                    "speaker_id": "m970n6z2cax863gzfh75c1rqq98c8kxg",
                    "title": "Upload your slides"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "delete": {
        "operationId": "deleteTask",
        "tags": [
          "Tasks"
        ],
        "summary": "Delete a task",
        "description": "Removes the task from the speaker's portal. Requires the admin role.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `event_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:events",
        "x-rate-limit-bucket": "event_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/taskId"
          }
        ],
        "responses": {
          "204": {
            "description": "No content.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/tasks/create": {
      "post": {
        "operationId": "createTask",
        "tags": [
          "Tasks"
        ],
        "summary": "Assign a task",
        "description": "Assigns one task to one or many speakers, named by `speaker_ids` or simply by `speaker_emails`. One task row is created per speaker, all of them returned in `results`.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `event_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:events",
        "x-rate-limit-bucket": "event_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/TaskWriteBody"
              },
              "example": {
                "title": "Upload your slides",
                "instructions": "16:9, PDF or PPTX, under 50 MB please.",
                "kind": "upload",
                "due_at": "2026-09-01T17:00:00.000Z",
                "speaker_emails": [
                  "grace@example.com",
                  "ada@example.com"
                ]
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/TaskCreateEnvelope"
                },
                "example": {
                  "data": {
                    "id": "k47abc…",
                    "title": "Upload your slides",
                    "instructions": "16:9, PDF or PPTX, under 50 MB please.",
                    "kind": "upload",
                    "due_at": "2026-09-01T17:00:00.000Z",
                    "completed_at": null,
                    "is_complete": false,
                    "is_overdue": false,
                    "speaker_id": "k57abc…",
                    "speaker": {
                      "id": "k57abc…",
                      "full_name": "Grace Hopper",
                      "email": "grace@example.com"
                    },
                    "session_id": null,
                    "session_title": null,
                    "form_id": null,
                    "created_at": "2026-08-11T09:12:44.001Z"
                  },
                  "results": [
                    {
                      "id": "k47abc…",
                      "title": "Upload your slides",
                      "speaker_id": "k57abc…"
                    }
                  ],
                  "created": 2
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/tracks": {
      "get": {
        "operationId": "listTracks",
        "tags": [
          "Event Settings"
        ],
        "summary": "List tracks",
        "description": "Every track configured on the event.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          },
          {
            "$ref": "#/components/parameters/search"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataPage"
                },
                "example": {
                  "data": [
                    {
                      "color": "#2F5CE0",
                      "created_at": "2026-08-11T19:27:45.331Z",
                      "event_id": "j976eyym787qhaq02v0nea4k7x8c879q",
                      "id": "kd70s9jv39zmvkarkyrjcbk14x8c8g9d",
                      "name": "AI Engineering",
                      "order": 0,
                      "updated_at": "2026-08-11T19:27:45.331Z"
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 25,
                    "page_size": 25,
                    "totalPages": 1,
                    "totalResults": 3,
                    "total_pages": 1,
                    "total_results": 3
                  },
                  "results": [
                    {
                      "color": "#2F5CE0",
                      "created_at": "2026-08-11T19:27:45.331Z",
                      "event_id": "j976eyym787qhaq02v0nea4k7x8c879q",
                      "id": "kd70s9jv39zmvkarkyrjcbk14x8c8g9d",
                      "name": "AI Engineering",
                      "order": 0,
                      "updated_at": "2026-08-11T19:27:45.331Z"
                    }
                  ],
                  "unknownResource": false
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "post": {
        "operationId": "searchTracks",
        "tags": [
          "Event Settings"
        ],
        "summary": "Search tracks",
        "description": "Same data as the list form, with the search body Sessionboard clients send.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataSearchBody"
              },
              "example": {
                "filters": {
                  "search": "ai"
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataPage"
                },
                "example": {
                  "data": [
                    {
                      "color": "#2F5CE0",
                      "created_at": "2026-08-11T13:14:41.555Z",
                      "event_id": "j97cxpcsg4nak46natxjzfxwj18c8e7j",
                      "id": "kd707gmqy2757zv5smcg1ey07h8c8ax6",
                      "name": "AI Engineering",
                      "order": 0,
                      "updated_at": "2026-08-11T13:14:41.555Z"
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 25,
                    "page_size": 25,
                    "totalPages": 1,
                    "totalResults": 3,
                    "total_pages": 1,
                    "total_results": 3
                  },
                  "results": [
                    {
                      "color": "#2F5CE0",
                      "created_at": "2026-08-11T13:14:41.555Z",
                      "event_id": "j97cxpcsg4nak46natxjzfxwj18c8e7j",
                      "id": "kd707gmqy2757zv5smcg1ey07h8c8ax6",
                      "name": "AI Engineering",
                      "order": 0,
                      "updated_at": "2026-08-11T13:14:41.555Z"
                    }
                  ],
                  "unknownResource": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/tracks/{id}": {
      "put": {
        "operationId": "updateTrack",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Update a track",
        "description": "Renames or reorders a track.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataWriteBody"
              },
              "example": {
                "name": "Applied AI & Agents"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataEnvelope"
                },
                "example": {
                  "data": {
                    "color": "#2F5CE0",
                    "created_at": "2026-08-11T13:14:41.555Z",
                    "event_id": "j97cxpcsg4nak46natxjzfxwj18c8e7j",
                    "id": "kd707gmqy2757zv5smcg1ey07h8c8ax6",
                    "name": "AI Engineering",
                    "order": 0,
                    "updated_at": "2026-08-11T13:14:41.555Z"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "delete": {
        "operationId": "deleteTrack",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Delete a track",
        "description": "Deletes the track and clears it from every session that referenced it.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          },
          {
            "$ref": "#/components/parameters/id"
          }
        ],
        "responses": {
          "204": {
            "description": "No content.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/event/{eventRef}/tracks/create": {
      "post": {
        "operationId": "createTrack",
        "tags": [
          "Metadata Writes"
        ],
        "summary": "Create a track",
        "description": "Adds a track to the event.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:metadata` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `metadata_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:metadata",
        "x-rate-limit-bucket": "metadata_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/MetadataWriteBody"
              },
              "example": {
                "name": "Applied AI",
                "color": "#0F6E70",
                "order": 10
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MetadataEnvelope"
                },
                "example": {
                  "data": {
                    "color": "#2F5CE0",
                    "created_at": "2026-08-11T13:14:41.555Z",
                    "event_id": "j97cxpcsg4nak46natxjzfxwj18c8e7j",
                    "id": "kd707gmqy2757zv5smcg1ey07h8c8ax6",
                    "name": "AI Engineering",
                    "order": 0,
                    "updated_at": "2026-08-11T13:14:41.555Z"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/events": {
      "get": {
        "operationId": "listEvents",
        "tags": [
          "Events"
        ],
        "summary": "List events",
        "description": "Every event in every workspace the credential belongs to, newest first. The read-only demo token sees all demo events.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.",
        "x-required-scope": "read:events",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/page"
          },
          {
            "$ref": "#/components/parameters/pageSize"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventsPage"
                },
                "example": {
                  "data": [
                    {
                      "_id": "j9746m4hzzc2ch16962hyz616x8c9r0h",
                      "agenda_published_at": null,
                      "background_url": null,
                      "created_at": "2026-08-11T19:27:45.331Z",
                      "description": "A single-track day for the people who maintain design systems, and everyone who has to live with them.",
                      "endsAt": 1793919600000,
                      "ends_at": "2026-11-05T23:00:00.000Z",
                      "features": {
                        "custom_fields": true,
                        "translated_fields": false,
                        "webhooks": true
                      },
                      "id": "j9746m4hzzc2ch16962hyz616x8c9r0h",
                      "logo_url": null,
                      "name": "Design Systems Day",
                      "organization_id": "mn7fs8btg5szyhbkqdfhtd4xmn8c8xhg",
                      "portal_settings": {
                        "allow_submission_edits": true,
                        "always_show_tasks": false,
                        "extend_task_deadlines": true
                      },
                      "public_url": "/e/ai-engineer/design-systems-day",
                      "slug": "design-systems-day",
                      "startsAt": 1793887200000,
                      "starts_at": "2026-11-05T14:00:00.000Z",
                      "timezone": "America/New_York",
                      "type": "Meetup",
                      "venue": "Brooklyn Expo Center, New York",
                      "website_url": null
                    }
                  ],
                  "pagination": {
                    "currentPage": 1,
                    "current_page": 1,
                    "pageSize": 1,
                    "page_size": 1,
                    "totalPages": 105,
                    "totalResults": 105,
                    "total_pages": 105,
                    "total_results": 105
                  },
                  "results": [
                    {
                      "_id": "j9746m4hzzc2ch16962hyz616x8c9r0h",
                      "agenda_published_at": null,
                      "background_url": null,
                      "created_at": "2026-08-11T19:27:45.331Z",
                      "description": "A single-track day for the people who maintain design systems, and everyone who has to live with them.",
                      "endsAt": 1793919600000,
                      "ends_at": "2026-11-05T23:00:00.000Z",
                      "features": {
                        "custom_fields": true,
                        "translated_fields": false,
                        "webhooks": true
                      },
                      "id": "j9746m4hzzc2ch16962hyz616x8c9r0h",
                      "logo_url": null,
                      "name": "Design Systems Day",
                      "organization_id": "mn7fs8btg5szyhbkqdfhtd4xmn8c8xhg",
                      "portal_settings": {
                        "allow_submission_edits": true,
                        "always_show_tasks": false,
                        "extend_task_deadlines": true
                      },
                      "public_url": "/e/ai-engineer/design-systems-day",
                      "slug": "design-systems-day",
                      "startsAt": 1793887200000,
                      "starts_at": "2026-11-05T14:00:00.000Z",
                      "timezone": "America/New_York",
                      "type": "Meetup",
                      "venue": "Brooklyn Expo Center, New York",
                      "website_url": null
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "post": {
        "operationId": "createEvent",
        "tags": [
          "Events"
        ],
        "summary": "Create an event",
        "description": "Stands up a new event in one of your workspaces. `organization_id` is optional when you administer exactly one workspace. The public address is derived from `slug` (or the name) and is never rejected for being taken — a clash is suffixed and the address you actually got comes back on the response with `slug_adjusted: true`. Requires the admin role in the workspace.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `event_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:events",
        "x-rate-limit-bucket": "event_writes",
        "x-demo-token-allowed": false,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EventWriteBody"
              },
              "example": {
                "name": "AI Summit 2026",
                "slug": "ai-summit-2026",
                "timezone": "America/Los_Angeles",
                "type": "Conference",
                "venue": "Moscone West, San Francisco",
                "starts_at": "2026-09-14T09:00:00.000Z",
                "ends_at": "2026-09-16T18:00:00.000Z",
                "website_url": "https://aisummit.example.com"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventEnvelope"
                },
                "example": {
                  "data": {
                    "_id": "j97anpvjehq8w0at0d7zqef8418c9h51",
                    "agenda_published_at": null,
                    "background_url": null,
                    "created_at": "2026-08-11T13:10:05.999Z",
                    "description": "A single-track day for the people who maintain design systems, and everyone who has to live with them.",
                    "endsAt": 1793919600000,
                    "ends_at": "2026-11-05T23:00:00.000Z",
                    "features": {
                      "custom_fields": true,
                      "translated_fields": false,
                      "webhooks": true
                    },
                    "id": "j97anpvjehq8w0at0d7zqef8418c9h51",
                    "logo_url": null,
                    "name": "Design Systems Day",
                    "organization_id": "mn7fs8btg5szyhbkqdfhtd4xmn8c8xhg",
                    "portal_settings": {
                      "allow_submission_edits": true,
                      "always_show_tasks": false,
                      "extend_task_deadlines": true
                    },
                    "public_url": "/e/design-systems-day",
                    "slug": "design-systems-day",
                    "startsAt": 1793887200000,
                    "starts_at": "2026-11-05T14:00:00.000Z",
                    "timezone": "America/New_York",
                    "type": "Meetup",
                    "venue": "Brooklyn Expo Center, New York",
                    "website_url": null
                  },
                  "slug_adjusted": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/events/{eventRef}": {
      "get": {
        "operationId": "getEvent",
        "tags": [
          "Events"
        ],
        "summary": "Get an event",
        "description": "One event in full, with totals for rooms, tracks, forms, sessions, abstracts, accepted and scheduled — so “did my import land?” is one call rather than five.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.\n\n**Rate limit** 100 requests / 15 minutes per key in the `entity_reads` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "read:events",
        "x-rate-limit-bucket": "entity_reads",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventDetailEnvelope"
                },
                "example": {
                  "data": {
                    "_id": "j976eyym787qhaq02v0nea4k7x8c879q",
                    "agenda_published_at": "2026-08-06T19:27:45.331Z",
                    "background_url": null,
                    "created_at": "2026-08-11T19:27:45.331Z",
                    "description": "Two days for the people building AI systems that have to work on Monday morning. Practitioner talks on evaluation, agents, retrieval, inference infrastructure and the product decisions in between — no keynote fluff, no vendor pitches.",
                    "endsAt": 1791939600000,
                    "ends_at": "2026-10-14T01:00:00.000Z",
                    "features": {
                      "custom_fields": true,
                      "translated_fields": false,
                      "webhooks": true
                    },
                    "id": "j976eyym787qhaq02v0nea4k7x8c879q",
                    "logo_url": null,
                    "name": "AI Engineer Summit 2026",
                    "organization_id": "mn7fs8btg5szyhbkqdfhtd4xmn8c8xhg",
                    "portal_settings": {
                      "allow_submission_edits": true,
                      "always_show_tasks": false,
                      "extend_task_deadlines": true
                    },
                    "public_url": "/e/ai-engineer/ai-summit-2026",
                    "slug": "ai-summit-2026",
                    "startsAt": 1791820800000,
                    "starts_at": "2026-10-12T16:00:00.000Z",
                    "timezone": "America/Los_Angeles",
                    "totals": {
                      "abstracts": 18,
                      "accepted": 9,
                      "forms": 1,
                      "rooms": 2,
                      "scheduled": 9,
                      "sessions": 2,
                      "tracks": 3
                    },
                    "type": "Conference",
                    "venue": "Moscone West, San Francisco",
                    "websiteUrl": "https://example.com/ai-summit-2026",
                    "website_url": "https://example.com/ai-summit-2026"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "put": {
        "operationId": "updateEvent",
        "tags": [
          "Events"
        ],
        "summary": "Update an event",
        "description": "Partial update of the event's details, dates, venue and speaker-portal behaviour. Renaming the public address follows the same never-blocked rule as create. Requires the admin role.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `event_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:events",
        "x-rate-limit-bucket": "event_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EventWriteBody"
              },
              "example": {
                "venue": "Moscone Center, Hall B",
                "ends_at": "2026-09-17T18:00:00.000Z",
                "portal_settings": {
                  "allow_submission_edits": false
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EventEnvelope"
                },
                "example": {
                  "data": {
                    "_id": "j97anpvjehq8w0at0d7zqef8418c9h51",
                    "agenda_published_at": null,
                    "background_url": null,
                    "created_at": "2026-08-11T13:10:05.999Z",
                    "description": "A single-track day for the people who maintain design systems, and everyone who has to live with them.",
                    "endsAt": 1793919600000,
                    "ends_at": "2026-11-05T23:00:00.000Z",
                    "features": {
                      "custom_fields": true,
                      "translated_fields": false,
                      "webhooks": true
                    },
                    "id": "j97anpvjehq8w0at0d7zqef8418c9h51",
                    "logo_url": null,
                    "name": "Design Systems Day",
                    "organization_id": "mn7fs8btg5szyhbkqdfhtd4xmn8c8xhg",
                    "portal_settings": {
                      "allow_submission_edits": true,
                      "always_show_tasks": false,
                      "extend_task_deadlines": true
                    },
                    "public_url": "/e/design-systems-day",
                    "slug": "design-systems-day",
                    "startsAt": 1793887200000,
                    "starts_at": "2026-11-05T14:00:00.000Z",
                    "timezone": "America/New_York",
                    "type": "Meetup",
                    "venue": "Brooklyn Expo Center, New York",
                    "website_url": null
                  },
                  "slug_adjusted": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "delete": {
        "operationId": "deleteEvent",
        "tags": [
          "Events"
        ],
        "summary": "Delete an event",
        "description": "Deletes the event and everything in it — sessions, speakers, forms, files (blobs included), tasks, evaluation plans, messages and history — through the same cascade the organizer's own “Delete event” dialog runs. This one is not recoverable. Requires the admin role.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `event_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:events",
        "x-rate-limit-bucket": "event_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/eventRef"
          }
        ],
        "responses": {
          "204": {
            "description": "No content.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/webhooks": {
      "get": {
        "operationId": "listWebhooks",
        "tags": [
          "Webhooks"
        ],
        "summary": "List webhook endpoints",
        "description": "Every endpoint in the workspaces you belong to. Signing secrets are masked here — the full value is shown once, when the endpoint is created or its secret rotated.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.",
        "x-required-scope": "read:events",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/event"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookListEnvelope"
                },
                "example": {
                  "data": [
                    {
                      "id": "k77abc…",
                      "url": "https://hooks.example.com/trackstage",
                      "events": [
                        "session.created",
                        "session.updated",
                        "decision.committed"
                      ],
                      "description": "Programme mirror",
                      "enabled": true,
                      "event_id": "k97abc…",
                      "secret_masked": "whsec_9c1f4…0513",
                      "created_at": "2026-07-28T08:15:00.000Z",
                      "updated_at": "2026-08-11T09:12:44.001Z",
                      "last_delivery_at": "2026-08-11T09:12:45.220Z",
                      "last_status": 200
                    }
                  ],
                  "results": [
                    {
                      "id": "k77abc…",
                      "url": "https://hooks.example.com/trackstage",
                      "events": [
                        "session.created",
                        "session.updated",
                        "decision.committed"
                      ],
                      "description": "Programme mirror",
                      "enabled": true,
                      "event_id": "k97abc…",
                      "secret_masked": "whsec_9c1f4…0513",
                      "created_at": "2026-07-28T08:15:00.000Z",
                      "updated_at": "2026-08-11T09:12:44.001Z",
                      "last_delivery_at": "2026-08-11T09:12:45.220Z",
                      "last_status": 200
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "post": {
        "operationId": "createWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Create a webhook endpoint",
        "description": "Subscribes an HTTPS endpoint to a set of event types (`[\"*\"]` for all). The response is the only time the signing secret is returned in full. Requires the admin role.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `event_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:events",
        "x-rate-limit-bucket": "event_writes",
        "x-demo-token-allowed": false,
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookWriteBody"
              },
              "example": {
                "url": "https://hooks.example.com/trackstage",
                "events": [
                  "session.created",
                  "session.updated",
                  "decision.committed"
                ],
                "description": "Programme mirror",
                "event": "ai-summit-2026"
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Created.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEnvelope"
                },
                "example": {
                  "data": {
                    "id": "k77abc…",
                    "url": "https://hooks.example.com/trackstage",
                    "events": [
                      "session.created",
                      "session.updated",
                      "decision.committed"
                    ],
                    "description": "Programme mirror",
                    "enabled": true,
                    "event_id": "k97abc…",
                    "secret_masked": "whsec_9c1f4…0513",
                    "created_at": "2026-07-28T08:15:00.000Z",
                    "updated_at": "2026-08-11T09:12:44.001Z",
                    "last_delivery_at": "2026-08-11T09:12:45.220Z",
                    "last_status": 200,
                    "secret": "whsec_9c1f4a7e2b8d0356f1a9c4e7b2d80513"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/webhooks/{webhookId}": {
      "get": {
        "operationId": "getWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Get a webhook endpoint",
        "description": "The endpoint plus its 25 most recent delivery attempts.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.",
        "x-required-scope": "read:events",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/webhookId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDetailEnvelope"
                },
                "example": {
                  "data": {
                    "id": "k77abc…",
                    "url": "https://hooks.example.com/trackstage",
                    "events": [
                      "session.created",
                      "session.updated",
                      "decision.committed"
                    ],
                    "description": "Programme mirror",
                    "enabled": true,
                    "event_id": "k97abc…",
                    "secret_masked": "whsec_9c1f4…0513",
                    "created_at": "2026-07-28T08:15:00.000Z",
                    "updated_at": "2026-08-11T09:12:44.001Z",
                    "last_delivery_at": "2026-08-11T09:12:45.220Z",
                    "last_status": 200,
                    "deliveries": [
                      {
                        "id": "k87abc…",
                        "webhook_id": "k77abc…",
                        "event": "session.updated",
                        "status": "succeeded",
                        "attempts": 1,
                        "response_status": 200,
                        "error": null,
                        "payload": "{\"data\":{\"id\":\"k17abc…\",\"title\":\"Designing agent workflows\",\"sourceOfChange\":\"api\"},\"metadata\":{\"action\":\"session.updated\",\"event_id\":\"k97abc…\",\"version\":\"1\"}}",
                        "created_at": "2026-08-11T09:12:45.001Z",
                        "delivered_at": "2026-08-11T09:12:45.220Z"
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "put": {
        "operationId": "updateWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Update a webhook endpoint",
        "description": "Change the URL, the subscribed event types, the description, or disable it. Requires the admin role.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `event_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:events",
        "x-rate-limit-bucket": "event_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/webhookId"
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookWriteBody"
              },
              "example": {
                "events": [
                  "*"
                ],
                "enabled": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEnvelope"
                },
                "example": {
                  "data": {
                    "id": "k77abc…",
                    "url": "https://hooks.example.com/trackstage",
                    "events": [
                      "session.created",
                      "session.updated",
                      "decision.committed"
                    ],
                    "description": "Programme mirror",
                    "enabled": true,
                    "event_id": "k97abc…",
                    "secret_masked": "whsec_9c1f4…0513",
                    "created_at": "2026-07-28T08:15:00.000Z",
                    "updated_at": "2026-08-11T09:12:44.001Z",
                    "last_delivery_at": "2026-08-11T09:12:45.220Z",
                    "last_status": 200
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/E400"
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      },
      "delete": {
        "operationId": "deleteWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Delete a webhook endpoint",
        "description": "Removes the endpoint and its delivery log. Requires the admin role.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `event_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:events",
        "x-rate-limit-bucket": "event_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/webhookId"
          }
        ],
        "responses": {
          "204": {
            "description": "No content.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/webhooks/{webhookId}/deliveries": {
      "get": {
        "operationId": "listWebhookDeliveries",
        "tags": [
          "Webhooks"
        ],
        "summary": "List delivery attempts",
        "description": "The delivery log for one endpoint, newest first, including the exact signed payload, the response status and any error.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `read:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\nThe read-only demo token can call this.",
        "x-required-scope": "read:events",
        "x-demo-token-allowed": true,
        "parameters": [
          {
            "$ref": "#/components/parameters/webhookId"
          },
          {
            "$ref": "#/components/parameters/limit"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookDeliveryListEnvelope"
                },
                "example": {
                  "data": [
                    {
                      "id": "k87abc…",
                      "webhook_id": "k77abc…",
                      "event": "session.updated",
                      "status": "succeeded",
                      "attempts": 1,
                      "response_status": 200,
                      "error": null,
                      "payload": "{\"data\":{\"id\":\"k17abc…\",\"title\":\"Designing agent workflows\",\"sourceOfChange\":\"api\"},\"metadata\":{\"action\":\"session.updated\",\"event_id\":\"k97abc…\",\"version\":\"1\"}}",
                      "created_at": "2026-08-11T09:12:45.001Z",
                      "delivered_at": "2026-08-11T09:12:45.220Z"
                    }
                  ],
                  "results": [
                    {
                      "id": "k87abc…",
                      "webhook_id": "k77abc…",
                      "event": "session.updated",
                      "status": "succeeded",
                      "attempts": 1,
                      "response_status": 200,
                      "error": null,
                      "payload": "{\"data\":{\"id\":\"k17abc…\",\"title\":\"Designing agent workflows\",\"sourceOfChange\":\"api\"},\"metadata\":{\"action\":\"session.updated\",\"event_id\":\"k97abc…\",\"version\":\"1\"}}",
                      "created_at": "2026-08-11T09:12:45.001Z",
                      "delivered_at": "2026-08-11T09:12:45.220Z"
                    }
                  ]
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/webhooks/{webhookId}/rotate": {
      "post": {
        "operationId": "rotateWebhookSecret",
        "tags": [
          "Webhooks"
        ],
        "summary": "Rotate the signing secret",
        "description": "Issues a new `whsec_…` secret and returns it in full, once. Deliveries in flight are signed with whichever secret was current when they were sent.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `event_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:events",
        "x-rate-limit-bucket": "event_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/webhookId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookEnvelope"
                },
                "example": {
                  "data": {
                    "id": "k77abc…",
                    "url": "https://hooks.example.com/trackstage",
                    "events": [
                      "session.created",
                      "session.updated",
                      "decision.committed"
                    ],
                    "description": "Programme mirror",
                    "enabled": true,
                    "event_id": "k97abc…",
                    "secret_masked": "whsec_4e7b2…1a9c",
                    "created_at": "2026-07-28T08:15:00.000Z",
                    "updated_at": "2026-08-11T09:12:44.001Z",
                    "last_delivery_at": "2026-08-11T09:12:45.220Z",
                    "last_status": 200,
                    "secret": "whsec_4e7b2d805139c1f4a7e2b8d0356f1a9c"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    },
    "/v1/webhooks/{webhookId}/test": {
      "post": {
        "operationId": "testWebhook",
        "tags": [
          "Webhooks"
        ],
        "summary": "Send a test delivery",
        "description": "Queues a signed `webhook.test` delivery so you can verify your receiver without waiting for a real change.\n\n**Authentication** — send a personal API key as `x-access-token: sb_live_…` **or** `Authorization: Bearer sb_live_…`. Both headers are first-class.\n\n**Scope** `write:events` — enforced only when the presenting key declares a scope set; an unscoped key acts with exactly its owner's workspace permissions, and declaring scopes can only narrow that. A 403 names the missing scope.\n\n**Write** — the read-only demo token (`demo-api-token`) answers 403 here.\n\n**Rate limit** 100 requests / 15 minutes per key in the `event_writes` bucket. Every response carries `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset`; a 429 adds `Retry-After`.",
        "x-required-scope": "write:events",
        "x-rate-limit-bucket": "event_writes",
        "x-demo-token-allowed": false,
        "parameters": [
          {
            "$ref": "#/components/parameters/webhookId"
          }
        ],
        "responses": {
          "200": {
            "description": "Success.",
            "headers": {
              "RateLimit-Limit": {
                "$ref": "#/components/headers/RateLimit-Limit"
              },
              "RateLimit-Remaining": {
                "$ref": "#/components/headers/RateLimit-Remaining"
              },
              "RateLimit-Reset": {
                "$ref": "#/components/headers/RateLimit-Reset"
              }
            },
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WebhookTestEnvelope"
                },
                "example": {
                  "data": {
                    "delivery_id": "k87abc…",
                    "status": "queued"
                  }
                }
              }
            }
          },
          "401": {
            "$ref": "#/components/responses/E401"
          },
          "403": {
            "$ref": "#/components/responses/E403"
          },
          "404": {
            "$ref": "#/components/responses/E404"
          },
          "429": {
            "$ref": "#/components/responses/E429"
          }
        },
        "security": [
          {
            "ApiKeyHeader": []
          },
          {
            "BearerToken": []
          }
        ]
      }
    }
  },
  "webhooks": {
    "delivery": {
      "post": {
        "operationId": "webhookDelivery",
        "tags": [
          "Webhooks"
        ],
        "summary": "Webhook delivery (sent BY Trackstage to your endpoint)",
        "description": "The request your registered endpoint receives. Respond 2xx to acknowledge; anything else is retried with exponential backoff.",
        "parameters": [
          {
            "name": "Trackstage-Signature",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "`t=<unix-seconds>,v1=<hex>` — HMAC-SHA256 over `\"{t}.{body}\"`."
          },
          {
            "name": "Trackstage-Event",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "The event type, e.g. `session.updated`."
          },
          {
            "name": "Trackstage-Delivery",
            "in": "header",
            "required": true,
            "schema": {
              "type": "string"
            },
            "description": "Unique delivery id — use it for idempotency."
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WebhookPayload"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Acknowledged. Any 2xx works."
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKeyHeader": {
        "type": "apiKey",
        "in": "header",
        "name": "x-access-token",
        "description": "A personal API key (`sb_live_…`), sent in Sessionboard's header so their clients work against this API unchanged.\n\n**Where to get one:** Account settings → **API & MCP** → *Create key*. The key is shown once, at creation — copy it then; it is stored only as a hash and cannot be shown again. Keys are revocable from the same screen and stop working immediately.\n\n**What it can reach:** the key resolves to a user, and every request re-runs the same workspace-membership and per-member event scoping the browser app runs. It can never reach an event its owner cannot.\n\n**Scopes:** optional. Unset means unrestricted within the owner's permissions; setting them can only narrow. Each operation names the scope it enforces (`x-required-scope`).\n\n**Exploring without an account:** `demo-api-token` reads the demo events and answers 403 on every write."
      },
      "BearerToken": {
        "type": "http",
        "scheme": "bearer",
        "bearerFormat": "sb_live_…",
        "description": "The same personal API key, sent as `Authorization: Bearer sb_live_…`. Interchangeable with `x-access-token` on every endpoint — pick whichever your HTTP client makes easier.\n\nAI agents have a separate door: the MCP server at `/mcp` speaks OAuth 2.1 + PKCE (discovery at `/.well-known/oauth-protected-resource`), and also accepts an `sb_live_…` key as a bearer token for non-interactive clients. See [the MCP reference](/docs/mcp)."
      }
    },
    "parameters": {
      "eventRef": {
        "name": "eventRef",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The event's slug (the one in its public URL) or its raw id. Both work everywhere.",
        "example": "ai-summit-2026"
      },
      "sessionId": {
        "name": "sessionId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The session id."
      },
      "speakerId": {
        "name": "speakerId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The speaker id."
      },
      "fileId": {
        "name": "fileId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The file id, or the upload id from an initiate/replace call."
      },
      "fieldId": {
        "name": "fieldId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The field's `internal_name`."
      },
      "webhookId": {
        "name": "webhookId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The webhook endpoint id."
      },
      "formId": {
        "name": "formId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The form's id, or its public slug (e.g. `cfp`). Both work.",
        "example": "cfp"
      },
      "taskId": {
        "name": "taskId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The task id."
      },
      "planId": {
        "name": "planId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The evaluation plan id."
      },
      "evaluatorId": {
        "name": "evaluatorId",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The evaluator id."
      },
      "speaker_id": {
        "name": "speaker_id",
        "in": "query",
        "schema": {
          "type": "string"
        },
        "description": "Restrict to one speaker."
      },
      "session_id": {
        "name": "session_id",
        "in": "query",
        "schema": {
          "type": "string"
        },
        "description": "Restrict to one session."
      },
      "plan_id": {
        "name": "plan_id",
        "in": "query",
        "schema": {
          "type": "string"
        },
        "description": "Restrict to one evaluation plan."
      },
      "evaluator_id": {
        "name": "evaluator_id",
        "in": "query",
        "schema": {
          "type": "string"
        },
        "description": "Restrict to one evaluator."
      },
      "id": {
        "name": "id",
        "in": "path",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The resource id. For form-backed value lists (tags, formats, levels, languages) this is the value itself, URL-encoded."
      },
      "page": {
        "name": "page",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "default": 1
        },
        "description": "1-based page number."
      },
      "pageSize": {
        "name": "pageSize",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 25
        },
        "description": "Rows per page, max 100. `page_size` is accepted as an alias."
      },
      "search": {
        "name": "search",
        "in": "query",
        "schema": {
          "type": "string"
        },
        "description": "Free-text filter."
      },
      "status": {
        "name": "status",
        "in": "query",
        "schema": {
          "type": "string"
        },
        "description": "Filter by status. On `/sessions` this is the pipeline status and passing it opts out of the accepted-only default; on `/forms` it is `open` or `closed`; on `/tasks` it is `open`, `completed` or `overdue`; on `/evaluation-plans` it is `open` or `closed`."
      },
      "is_abstract": {
        "name": "is_abstract",
        "in": "query",
        "schema": {
          "type": "boolean"
        },
        "description": "Restrict to abstracts (true) or programme sessions (false)."
      },
      "track_id": {
        "name": "track_id",
        "in": "query",
        "schema": {
          "type": "string"
        }
      },
      "tag_id": {
        "name": "tag_id",
        "in": "query",
        "schema": {
          "type": "string"
        }
      },
      "include_deleted": {
        "name": "include_deleted",
        "in": "query",
        "schema": {
          "type": "boolean"
        },
        "description": "Include soft-deleted rows — sessions on `/sessions`, archived statuses on `/statuses`. Each carries `deleted_at`."
      },
      "expand": {
        "name": "expand",
        "in": "query",
        "schema": {
          "type": "string"
        },
        "description": "Comma-separated. `files` inlines attachments; `deleted` lets a soft-deleted session be read."
      },
      "workflow_status": {
        "name": "workflow_status",
        "in": "query",
        "schema": {
          "type": "string",
          "enum": [
            "invited",
            "confirmed",
            "dropped"
          ]
        }
      },
      "event": {
        "name": "event",
        "in": "query",
        "schema": {
          "type": "string"
        },
        "description": "Restrict to endpoints scoped to this event (slug or id)."
      },
      "limit": {
        "name": "limit",
        "in": "query",
        "schema": {
          "type": "integer",
          "minimum": 1,
          "maximum": 100,
          "default": 25
        }
      },
      "secret": {
        "name": "secret",
        "in": "query",
        "required": true,
        "schema": {
          "type": "string"
        },
        "description": "The endpoint's `whsec_…` signing secret, so the sink can verify the HMAC."
      }
    },
    "headers": {
      "RateLimit-Limit": {
        "schema": {
          "type": "integer"
        },
        "description": "Requests allowed in the current window."
      },
      "RateLimit-Remaining": {
        "schema": {
          "type": "integer"
        },
        "description": "Requests left in the current window."
      },
      "RateLimit-Reset": {
        "schema": {
          "type": "integer"
        },
        "description": "Unix seconds at which the window resets."
      },
      "Retry-After": {
        "schema": {
          "type": "integer"
        },
        "description": "Seconds to wait before retrying."
      }
    },
    "responses": {
      "E400": {
        "description": "Bad request — the body or parameters are invalid. The message says what.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E401": {
        "description": "Missing or invalid API token.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E403": {
        "description": "The credential is valid but lacks the scope, role or workspace access this needs.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E404": {
        "description": "No such event, resource, or endpoint.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E409": {
        "description": "Stale update — the resource changed since you fetched it. Re-read and retry.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E413": {
        "description": "The file exceeds the 50 MB simple-upload ceiling. Use the two-phase flow.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      },
      "E429": {
        "description": "Rate limited. Wait for `Retry-After` seconds.",
        "headers": {
          "RateLimit-Limit": {
            "$ref": "#/components/headers/RateLimit-Limit"
          },
          "RateLimit-Remaining": {
            "$ref": "#/components/headers/RateLimit-Remaining"
          },
          "RateLimit-Reset": {
            "$ref": "#/components/headers/RateLimit-Reset"
          },
          "Retry-After": {
            "$ref": "#/components/headers/Retry-After"
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/Error"
            }
          }
        }
      }
    },
    "schemas": {
      "Error": {
        "type": "object",
        "description": "Every failure uses this shape. `error` and `message` are the same human sentence — `error` is where this API has always put it, `message` is where Sessionboard clients look. `code` is the machine-readable name.",
        "required": [
          "error",
          "code",
          "message",
          "status"
        ],
        "properties": {
          "error": {
            "type": "string",
            "examples": [
              "Session not found."
            ]
          },
          "code": {
            "type": "string",
            "examples": [
              "NotFoundError"
            ]
          },
          "message": {
            "type": "string",
            "examples": [
              "Session not found."
            ]
          },
          "status": {
            "type": "integer",
            "examples": [
              404
            ]
          }
        }
      },
      "Pagination": {
        "type": "object",
        "description": "Carries both spellings: camelCase (what this API has always returned) and snake_case (what Sessionboard's CRUD proxy returns). They always hold the same values.",
        "properties": {
          "currentPage": {
            "type": "integer",
            "examples": [
              1
            ]
          },
          "pageSize": {
            "type": "integer",
            "examples": [
              25
            ]
          },
          "totalPages": {
            "type": "integer",
            "examples": [
              4
            ]
          },
          "totalResults": {
            "type": "integer",
            "examples": [
              97
            ]
          },
          "current_page": {
            "type": "integer",
            "examples": [
              1
            ]
          },
          "page_size": {
            "type": "integer",
            "examples": [
              25
            ]
          },
          "total_pages": {
            "type": "integer",
            "examples": [
              4
            ]
          },
          "total_results": {
            "type": "integer",
            "examples": [
              97
            ]
          }
        }
      },
      "CustomFieldValue": {
        "type": "object",
        "description": "One answer to one CFP question. `value` is the flattened string Sessionboard clients expect; `value_raw` is the untouched JSON, so multi-selects and structured answers are never lossy.",
        "properties": {
          "id": {
            "type": "string",
            "examples": [
              "parity_notes"
            ]
          },
          "internal_name": {
            "type": "string",
            "examples": [
              "parity_notes"
            ]
          },
          "name": {
            "type": "string",
            "examples": [
              "Parity Notes"
            ]
          },
          "type": {
            "type": "string",
            "examples": [
              "long_text"
            ]
          },
          "value": {
            "type": "string"
          },
          "value_raw": {
            "description": "Any JSON value."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the answer's submission was created."
          }
        }
      },
      "ParticipantRole": {
        "type": "object",
        "nullable": true,
        "properties": {
          "slug": {
            "type": "string",
            "examples": [
              "speaker"
            ]
          },
          "name": {
            "type": "string",
            "examples": [
              "Speaker"
            ]
          },
          "name_plural": {
            "type": "string",
            "examples": [
              "Speakers"
            ]
          },
          "core_role": {
            "type": "string",
            "enum": [
              "speaker",
              "chairperson",
              "moderator"
            ]
          }
        }
      },
      "Speaker": {
        "type": "object",
        "description": "A person on the event. Carries the snake_case contact profile plus the camelCase aliases this API returned before the parity work.",
        "properties": {
          "id": {
            "type": "string"
          },
          "friendly_id": {
            "type": "string",
            "examples": [
              "SPK-20431"
            ]
          },
          "friendly_id_raw": {
            "type": "integer",
            "examples": [
              20431
            ]
          },
          "full_name": {
            "type": "string"
          },
          "first_name": {
            "type": "string"
          },
          "last_name": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "title": {
            "type": "string",
            "nullable": true
          },
          "company_name": {
            "type": "string",
            "nullable": true
          },
          "about": {
            "type": "string",
            "nullable": true
          },
          "phone_mobile": {
            "type": "string",
            "nullable": true
          },
          "pronouns": {
            "type": "string",
            "nullable": true
          },
          "salutation": {
            "type": "string",
            "nullable": true
          },
          "photo_url": {
            "type": "string",
            "format": "uri",
            "nullable": true
          },
          "website_url": {
            "type": "string",
            "nullable": true
          },
          "linkedin_url": {
            "type": "string",
            "nullable": true
          },
          "twitter_url": {
            "type": "string",
            "nullable": true
          },
          "workflow_status": {
            "type": "string",
            "nullable": true,
            "enum": [
              "invited",
              "confirmed",
              "dropped",
              null
            ]
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Creation time."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Last write."
          },
          "participant_role": {
            "$ref": "#/components/schemas/ParticipantRole"
          },
          "name": {
            "type": "string",
            "description": "Legacy alias of `full_name`."
          },
          "firstName": {
            "type": "string",
            "description": "Legacy alias of `first_name`."
          },
          "lastName": {
            "type": "string",
            "description": "Legacy alias of `last_name`."
          },
          "jobTitle": {
            "type": "string",
            "nullable": true,
            "description": "Legacy alias of `title`."
          },
          "company": {
            "type": "string",
            "nullable": true,
            "description": "Legacy alias of `company_name`."
          },
          "bio": {
            "type": "string",
            "nullable": true,
            "description": "Legacy alias of `about`."
          },
          "headshotUrl": {
            "type": "string",
            "nullable": true,
            "description": "Legacy alias of `photo_url`."
          }
        }
      },
      "NamedMetadata": {
        "type": "object",
        "nullable": true,
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "color": {
            "type": "string",
            "examples": [
              "#0F6E70"
            ]
          },
          "order": {
            "type": "integer"
          },
          "capacity": {
            "type": "integer",
            "nullable": true
          },
          "event_id": {
            "type": "string"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Creation time."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Last write."
          }
        }
      },
      "SessionStatus": {
        "type": "object",
        "description": "A status an organizer can put a session in. The seven built-ins ship with every event and cannot be deleted or re-categorised; custom ones are labels bound to a pipeline value, so the accept/decline machinery and the wording the speaker sees never disagree.",
        "properties": {
          "id": {
            "type": "string",
            "description": "The pipeline value for a built-in (`accepted`, `pending`, …), the row id for a custom status. This is what has always been returned here.",
            "examples": [
              "accepted"
            ]
          },
          "status_id": {
            "type": "string",
            "nullable": true,
            "description": "Always the row id. `null` on an event that has never edited its statuses and is still running on the built-in defaults."
          },
          "name": {
            "type": "string",
            "examples": [
              "Accepted"
            ]
          },
          "value": {
            "type": "string",
            "description": "The value `submissions.status` holds — what `?status=` filters on."
          },
          "pipeline_status": {
            "type": "string",
            "enum": [
              "draft",
              "pending",
              "accept_queue",
              "decline_queue",
              "accepted",
              "declined",
              "withdrawn"
            ]
          },
          "category": {
            "type": "string",
            "enum": [
              "draft",
              "pending",
              "accepted",
              "declined",
              "withdrawn"
            ]
          },
          "color": {
            "type": "string",
            "enum": [
              "green",
              "amber",
              "red",
              "gray",
              "blue"
            ]
          },
          "order": {
            "type": "integer"
          },
          "system": {
            "type": "boolean",
            "description": "A built-in the pipeline needs."
          },
          "system_key": {
            "type": "string",
            "nullable": true
          },
          "created_by": {
            "type": "string",
            "nullable": true,
            "description": "`null` reads as “System”."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Creation time; null for built-ins."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Last write."
          },
          "deleted_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Set when archived — restore it with POST /statuses/{id}/restore."
          }
        }
      },
      "SessionFile": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri",
            "nullable": true
          },
          "title": {
            "type": "string"
          },
          "filename": {
            "type": "string"
          },
          "size": {
            "type": "integer",
            "nullable": true
          },
          "mimetype": {
            "type": "string",
            "nullable": true
          },
          "version": {
            "type": "integer"
          },
          "approval_status": {
            "type": "string",
            "enum": [
              "pending",
              "approved",
              "changes_requested"
            ]
          },
          "review_note": {
            "type": "string",
            "nullable": true
          },
          "session_id": {
            "type": "string",
            "nullable": true
          },
          "assigned_participant_id": {
            "type": "string",
            "nullable": true
          },
          "assigned_participant_email": {
            "type": "string",
            "nullable": true
          },
          "assigned_participant_name": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Upload time."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Last write."
          }
        }
      },
      "Session": {
        "type": "object",
        "description": "A session or abstract. The union of Sessionboard's `Session` shape and every field this API returned before parity, so it is a strict superset of both.",
        "properties": {
          "id": {
            "type": "string"
          },
          "friendly_id": {
            "type": "string",
            "examples": [
              "SESS-73041"
            ]
          },
          "friendly_id_raw": {
            "type": "integer",
            "examples": [
              73041
            ]
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "pending",
              "accept_queue",
              "decline_queue",
              "accepted",
              "declined",
              "withdrawn"
            ]
          },
          "is_abstract": {
            "type": "boolean",
            "description": "True for CFP submissions, false for programme sessions."
          },
          "kind": {
            "type": "string",
            "enum": [
              "abstract",
              "session"
            ]
          },
          "is_public": {
            "type": "boolean"
          },
          "starts_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Scheduled start."
          },
          "ends_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Scheduled end, derived from duration."
          },
          "duration_minutes": {
            "type": "integer",
            "nullable": true
          },
          "capacity": {
            "type": "integer",
            "nullable": true,
            "description": "Assigned room's capacity."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Submission time."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Concurrency token — send this back on PUT."
          },
          "deleted_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Set when soft-deleted."
          },
          "decided_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the accept/decline decision was committed."
          },
          "notified_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the decision email went out."
          },
          "custom_fields": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/CustomFieldValue"
            }
          },
          "answers": {
            "type": "object",
            "additionalProperties": true,
            "description": "The raw answer map keyed by field `internal_name`."
          },
          "speakers": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Speaker"
            }
          },
          "chairpersons": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Speaker"
            }
          },
          "moderators": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Speaker"
            }
          },
          "participants": {
            "type": "array",
            "description": "Every participant in one flat list, each with `participant_role`.",
            "items": {
              "$ref": "#/components/schemas/Speaker"
            }
          },
          "submitter": {
            "$ref": "#/components/schemas/Speaker"
          },
          "tags": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NamedMetadata"
            }
          },
          "track": {
            "$ref": "#/components/schemas/NamedMetadata"
          },
          "room": {
            "$ref": "#/components/schemas/NamedMetadata"
          },
          "format": {
            "$ref": "#/components/schemas/NamedMetadata"
          },
          "level": {
            "$ref": "#/components/schemas/NamedMetadata"
          },
          "language": {
            "$ref": "#/components/schemas/NamedMetadata"
          },
          "subsessions": {
            "type": "array",
            "items": {},
            "description": "Always empty — this product has no parent/child sessions. Present so clients written against Sessionboard can iterate it without a guard."
          },
          "files": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SessionFile"
            },
            "description": "Only present when `expand=files` is requested."
          },
          "startTime": {
            "type": "integer",
            "nullable": true,
            "description": "Legacy: start in epoch ms."
          },
          "endTime": {
            "type": "integer",
            "nullable": true,
            "description": "Legacy: end in epoch ms."
          },
          "durationMinutes": {
            "type": "integer",
            "nullable": true,
            "description": "Legacy alias."
          },
          "location": {
            "type": "string",
            "nullable": true,
            "description": "Legacy: room name."
          },
          "trackColor": {
            "type": "string",
            "nullable": true,
            "description": "Legacy: track colour."
          },
          "submittedAt": {
            "type": "integer",
            "description": "Legacy: creation time in epoch ms."
          },
          "decidedAt": {
            "type": "integer",
            "nullable": true,
            "description": "Legacy alias in epoch ms."
          }
        }
      },
      "SessionStatusRow": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "friendly_id": {
            "type": "string"
          },
          "friendly_id_raw": {
            "type": "integer"
          },
          "status": {
            "type": "string"
          },
          "is_abstract": {
            "type": "boolean"
          },
          "deleted_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Set when soft-deleted."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Creation time."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Last write."
          },
          "subsessions": {
            "type": "array",
            "items": {}
          }
        }
      },
      "Event": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string"
          },
          "slug": {
            "type": "string"
          },
          "type": {
            "type": "string",
            "nullable": true
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "venue": {
            "type": "string",
            "nullable": true
          },
          "website_url": {
            "type": "string",
            "nullable": true
          },
          "timezone": {
            "type": "string",
            "examples": [
              "America/Los_Angeles"
            ]
          },
          "starts_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Event start."
          },
          "ends_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Event end."
          },
          "logo_url": {
            "type": "string",
            "nullable": true
          },
          "background_url": {
            "type": "string",
            "nullable": true
          },
          "agenda_published_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Set once the public programme is live."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Creation time."
          },
          "organization_id": {
            "type": "string",
            "nullable": true,
            "description": "The workspace this event belongs to."
          },
          "public_url": {
            "type": "string",
            "examples": [
              "/e/ai-engineer/ai-summit-2026"
            ]
          },
          "portal_settings": {
            "type": "object",
            "description": "How the speaker portal behaves for this event.",
            "properties": {
              "always_show_tasks": {
                "type": "boolean"
              },
              "allow_submission_edits": {
                "type": "boolean"
              },
              "extend_task_deadlines": {
                "type": "boolean"
              }
            }
          },
          "features": {
            "type": "object",
            "properties": {
              "translated_fields": {
                "type": "boolean"
              },
              "custom_fields": {
                "type": "boolean"
              },
              "webhooks": {
                "type": "boolean"
              }
            }
          },
          "_id": {
            "type": "string",
            "description": "Legacy alias of `id`."
          },
          "startsAt": {
            "type": "integer",
            "nullable": true,
            "description": "Legacy: epoch ms."
          },
          "endsAt": {
            "type": "integer",
            "nullable": true,
            "description": "Legacy: epoch ms."
          },
          "websiteUrl": {
            "type": "string",
            "nullable": true,
            "description": "Legacy alias."
          }
        }
      },
      "Field": {
        "type": "object",
        "description": "A field definition. These come from the CFP form's questions — custom fields and form questions are one and the same in this product.",
        "properties": {
          "id": {
            "type": "string",
            "examples": [
              "format"
            ]
          },
          "internal_name": {
            "type": "string",
            "examples": [
              "format"
            ]
          },
          "public_name": {
            "type": "string",
            "examples": [
              "Format"
            ]
          },
          "field_type": {
            "type": "string",
            "examples": [
              "dropdown"
            ],
            "description": "short_text | long_text | rich_text | dropdown | multi_select | email | url | phone | checkbox | file"
          },
          "field_source": {
            "type": "string",
            "enum": [
              "standard",
              "custom"
            ],
            "description": "`standard` for locked system fields, `custom` for organizer-added ones."
          },
          "contains_pii": {
            "type": "boolean"
          },
          "scope": {
            "type": "string",
            "enum": [
              "session",
              "contact"
            ]
          },
          "required": {
            "type": "boolean"
          },
          "enabled": {
            "type": "boolean"
          },
          "options": {
            "type": "array",
            "nullable": true,
            "items": {
              "type": "string"
            }
          },
          "help": {
            "type": "string",
            "nullable": true
          },
          "form_id": {
            "type": "string"
          },
          "form_slug": {
            "type": "string"
          },
          "createdAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Owning form's creation time."
          },
          "updatedAt": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Owning form's last write."
          }
        }
      },
      "Submission": {
        "type": "object",
        "description": "The pre-parity submission shape, unchanged.",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "kind": {
            "type": "string",
            "enum": [
              "abstract",
              "session"
            ]
          },
          "status": {
            "type": "string"
          },
          "track": {
            "type": "string",
            "nullable": true
          },
          "format": {
            "type": "string",
            "nullable": true
          },
          "level": {
            "type": "string",
            "nullable": true
          },
          "language": {
            "type": "string",
            "nullable": true
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "submittedAt": {
            "type": "integer"
          },
          "decidedAt": {
            "type": "integer",
            "nullable": true
          },
          "speakers": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "name": {
                  "type": "string"
                },
                "email": {
                  "type": "string"
                },
                "role": {
                  "type": "string"
                },
                "jobTitle": {
                  "type": "string",
                  "nullable": true
                },
                "company": {
                  "type": "string",
                  "nullable": true
                }
              }
            }
          }
        }
      },
      "Webhook": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Subscribed event types, or `[\"*\"]` for all of them."
          },
          "description": {
            "type": "string",
            "nullable": true
          },
          "enabled": {
            "type": "boolean"
          },
          "event_id": {
            "type": "string",
            "nullable": true,
            "description": "Null for workspace-wide endpoints."
          },
          "org_id": {
            "type": "string"
          },
          "secret": {
            "type": "string",
            "description": "Full `whsec_…` value on create and rotate; masked (`whsec_1a2b3c4d…ef01`) everywhere else."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Creation time."
          },
          "last_delivery_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Most recent attempt."
          },
          "last_status": {
            "type": "integer",
            "nullable": true
          },
          "last_error": {
            "type": "string",
            "nullable": true
          },
          "consecutive_failures": {
            "type": "integer"
          }
        }
      },
      "WebhookDelivery": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "event_type": {
            "type": "string",
            "examples": [
              "session.updated"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "pending",
              "success",
              "failed"
            ]
          },
          "attempts": {
            "type": "integer"
          },
          "response_status": {
            "type": "integer",
            "nullable": true
          },
          "error": {
            "type": "string",
            "nullable": true
          },
          "payload": {
            "type": "string",
            "description": "The exact JSON body that was signed."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Queued at."
          },
          "delivered_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Succeeded at."
          }
        }
      },
      "WebhookPayload": {
        "type": "object",
        "description": "The body POSTed to your endpoint. Signed with `Trackstage-Signature: t=<unix-seconds>,v1=<hex>`, an HMAC-SHA256 over `\"{t}.{body}\"` using the endpoint's secret. Verify it before trusting the payload, and reject timestamps outside your tolerance to prevent replay.",
        "required": [
          "data",
          "metadata"
        ],
        "properties": {
          "data": {
            "type": "object",
            "description": "The changed resource. Always carries `id` and `sourceOfChange`.",
            "additionalProperties": true,
            "properties": {
              "id": {
                "type": "string"
              },
              "sourceOfChange": {
                "type": "string",
                "enum": [
                  "user",
                  "agent"
                ]
              }
            }
          },
          "metadata": {
            "type": "object",
            "properties": {
              "action": {
                "type": "string",
                "examples": [
                  "session.updated"
                ]
              },
              "event_id": {
                "type": "string",
                "nullable": true
              },
              "org_id": {
                "type": "string"
              },
              "resource_url": {
                "type": "string",
                "nullable": true,
                "description": "Where to re-fetch the resource from this API."
              },
              "version": {
                "type": "integer",
                "examples": [
                  1
                ]
              },
              "datetime": {
                "type": "string",
                "format": "date-time"
              }
            }
          }
        }
      },
      "Agenda": {
        "type": "object",
        "properties": {
          "event": {
            "$ref": "#/components/schemas/Event"
          },
          "published": {
            "type": "boolean"
          },
          "published_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the programme went public."
          },
          "rooms": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NamedMetadata"
            }
          },
          "tracks": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NamedMetadata"
            }
          },
          "scheduled": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "starts_at": {
                  "type": "string",
                  "format": "date-time",
                  "nullable": true,
                  "description": "Slot start."
                },
                "ends_at": {
                  "type": "string",
                  "format": "date-time",
                  "nullable": true,
                  "description": "Slot end."
                },
                "duration_minutes": {
                  "type": "integer",
                  "nullable": true
                },
                "room_id": {
                  "type": "string",
                  "nullable": true
                },
                "track_id": {
                  "type": "string",
                  "nullable": true
                }
              }
            }
          },
          "unscheduled": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                }
              }
            }
          },
          "conflicts": {
            "type": "array",
            "items": {},
            "description": "Double-booked rooms and speakers, computed live."
          },
          "totals": {
            "type": "object",
            "properties": {
              "scheduled": {
                "type": "integer"
              },
              "unscheduled": {
                "type": "integer"
              },
              "conflicts": {
                "type": "integer"
              }
            }
          }
        }
      },
      "EchoResult": {
        "type": "object",
        "properties": {
          "received": {
            "type": "boolean"
          },
          "verified": {
            "type": "boolean",
            "nullable": true
          },
          "event": {
            "type": "string",
            "nullable": true
          },
          "delivery": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "FileBytesReceipt": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "size": {
                "type": "integer"
              },
              "received": {
                "type": "boolean"
              }
            }
          }
        }
      },
      "DateRangeFilter": {
        "type": "object",
        "description": "ISO-8601 or epoch milliseconds are both accepted.",
        "properties": {
          "before": {
            "type": "string",
            "format": "date-time"
          },
          "after": {
            "type": "string",
            "format": "date-time"
          }
        }
      },
      "SessionSearchBody": {
        "type": "object",
        "properties": {
          "filters": {
            "type": "object",
            "properties": {
              "status": {
                "type": "string",
                "enum": [
                  "draft",
                  "pending",
                  "accept_queue",
                  "decline_queue",
                  "accepted",
                  "declined",
                  "withdrawn"
                ]
              },
              "isAbstract": {
                "type": "boolean"
              },
              "trackId": {
                "type": "string"
              },
              "tagId": {
                "type": "string"
              },
              "search": {
                "type": "string",
                "description": "Matches title and description."
              },
              "includeDeleted": {
                "type": "boolean"
              },
              "createdAt": {
                "$ref": "#/components/schemas/DateRangeFilter"
              },
              "updatedAt": {
                "$ref": "#/components/schemas/DateRangeFilter"
              }
            }
          },
          "sort": {
            "type": "object",
            "properties": {
              "order": {
                "type": "string",
                "enum": [
                  "createdAt",
                  "updatedAt",
                  "startsAt",
                  "title"
                ]
              },
              "sort": {
                "type": "string",
                "enum": [
                  "asc",
                  "desc"
                ]
              }
            }
          },
          "expand": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "files",
                "deleted"
              ]
            }
          },
          "page": {
            "type": "integer",
            "minimum": 1
          },
          "pageSize": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        }
      },
      "SpeakerSearchBody": {
        "type": "object",
        "properties": {
          "filters": {
            "type": "object",
            "properties": {
              "search": {
                "type": "string"
              },
              "workflowStatus": {
                "type": "string",
                "enum": [
                  "invited",
                  "confirmed",
                  "dropped"
                ]
              }
            }
          },
          "sort": {
            "type": "object",
            "properties": {
              "sort": {
                "type": "string",
                "enum": [
                  "asc",
                  "desc"
                ]
              }
            }
          },
          "page": {
            "type": "integer",
            "minimum": 1
          },
          "pageSize": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        }
      },
      "MetadataSearchBody": {
        "type": "object",
        "properties": {
          "filters": {
            "type": "object",
            "properties": {
              "search": {
                "type": "string"
              }
            }
          },
          "page": {
            "type": "integer",
            "minimum": 1
          },
          "pageSize": {
            "type": "integer",
            "minimum": 1,
            "maximum": 100
          }
        }
      },
      "SessionWriteBody": {
        "type": "object",
        "description": "Every field is optional on update; `title` is required on create. snake_case and camelCase keys are both accepted, and times take ISO-8601 or epoch milliseconds.",
        "properties": {
          "title": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "status": {
            "type": "string",
            "enum": [
              "draft",
              "pending",
              "accept_queue",
              "decline_queue",
              "accepted",
              "declined",
              "withdrawn"
            ]
          },
          "is_abstract": {
            "type": "boolean",
            "description": "Create only — a session cannot change kind after creation."
          },
          "starts_at": {
            "type": "string",
            "format": "date-time"
          },
          "ends_at": {
            "type": "string",
            "format": "date-time",
            "description": "Converted to `duration_minutes` when that is not given."
          },
          "duration_minutes": {
            "type": "integer",
            "minimum": 5
          },
          "room_id": {
            "type": "string",
            "description": "Empty string clears the assignment."
          },
          "track_id": {
            "type": "string",
            "description": "Empty string clears the assignment."
          },
          "format": {
            "type": "string"
          },
          "level": {
            "type": "string"
          },
          "language": {
            "type": "string"
          },
          "tags": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "custom_fields": {
            "type": "object",
            "additionalProperties": true
          },
          "submitter_email": {
            "type": "string",
            "format": "email"
          },
          "submitter_first_name": {
            "type": "string"
          },
          "submitter_last_name": {
            "type": "string"
          },
          "speaker_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "description": "Optimistic concurrency token. A mismatch answers 409."
          }
        }
      },
      "CustomFieldsBody": {
        "type": "object",
        "required": [
          "custom_fields"
        ],
        "properties": {
          "custom_fields": {
            "type": "object",
            "additionalProperties": true,
            "description": "Values keyed by field `internal_name`."
          }
        }
      },
      "BulkOperations": {
        "type": "object",
        "required": [
          "operations"
        ],
        "properties": {
          "operations": {
            "type": "array",
            "maxItems": 100,
            "items": {
              "type": "object",
              "required": [
                "action"
              ],
              "properties": {
                "action": {
                  "type": "string",
                  "enum": [
                    "create",
                    "update",
                    "delete"
                  ]
                },
                "id": {
                  "type": "string",
                  "description": "Required for update and delete."
                },
                "data": {
                  "$ref": "#/components/schemas/SessionWriteBody"
                }
              }
            }
          }
        }
      },
      "BulkResponse": {
        "type": "object",
        "properties": {
          "batch_id": {
            "type": "string"
          },
          "results": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "index": {
                  "type": "integer"
                },
                "action": {
                  "type": "string"
                },
                "status": {
                  "type": "string",
                  "enum": [
                    "success",
                    "error"
                  ]
                },
                "id": {
                  "type": "string"
                },
                "error": {
                  "type": "object",
                  "properties": {
                    "code": {
                      "type": "string"
                    },
                    "message": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          },
          "stats": {
            "type": "object",
            "properties": {
              "total": {
                "type": "integer"
              },
              "succeeded": {
                "type": "integer"
              },
              "failed": {
                "type": "integer"
              }
            }
          }
        }
      },
      "SpeakerWriteBody": {
        "type": "object",
        "description": "`email` is required on create and ignored on update.",
        "properties": {
          "email": {
            "type": "string",
            "format": "email"
          },
          "first_name": {
            "type": "string"
          },
          "last_name": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "company_name": {
            "type": "string"
          },
          "about": {
            "type": "string"
          },
          "phone_mobile": {
            "type": "string"
          },
          "pronouns": {
            "type": "string"
          },
          "salutation": {
            "type": "string"
          },
          "website_url": {
            "type": "string"
          },
          "linkedin_url": {
            "type": "string"
          },
          "twitter_url": {
            "type": "string"
          },
          "workflow_status": {
            "type": "string",
            "enum": [
              "invited",
              "confirmed",
              "dropped"
            ]
          }
        }
      },
      "FieldWriteBody": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "The label organizers and speakers see."
          },
          "label": {
            "type": "string",
            "description": "Alias of `name`."
          },
          "type": {
            "type": "string",
            "description": "short_text | long_text | rich_text | dropdown | multi_select | email | url | phone | checkbox | file"
          },
          "required": {
            "type": "boolean"
          },
          "enabled": {
            "type": "boolean"
          },
          "help": {
            "type": "string"
          },
          "options": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "form_id": {
            "type": "string",
            "description": "Which form to add it to; defaults to the first."
          }
        }
      },
      "MetadataWriteBody": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string"
          },
          "color": {
            "type": "string",
            "description": "Tracks: any hex. Statuses: one of `green`, `amber`, `red`, `gray`, `blue`.",
            "examples": [
              "#0F6E70"
            ]
          },
          "capacity": {
            "type": "integer",
            "description": "Rooms only."
          },
          "order": {
            "type": "integer"
          },
          "category": {
            "type": "string",
            "enum": [
              "draft",
              "pending",
              "accepted",
              "declined",
              "withdrawn"
            ],
            "description": "Statuses only — the pipeline behaviour the label inherits. Defaults to `pending`. Built-in statuses refuse a category change."
          },
          "reassign_to": {
            "type": "string",
            "description": "Statuses only, on DELETE — where submissions carrying this label should land. Required when any still do."
          }
        }
      },
      "Form": {
        "type": "object",
        "description": "A call-for-speakers form. Its `questions[]` ARE the event's custom-field definitions, so this is the same object `GET /fields` describes, seen from the form's side.",
        "properties": {
          "id": {
            "type": "string"
          },
          "slug": {
            "type": "string",
            "examples": [
              "cfp"
            ]
          },
          "kind": {
            "type": "string",
            "enum": [
              "abstract",
              "session"
            ]
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "closed"
            ]
          },
          "is_open": {
            "type": "boolean",
            "description": "Status is open AND the close date has not passed."
          },
          "close_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the CFP closes."
          },
          "internal_name": {
            "type": "string"
          },
          "external_title": {
            "type": "string"
          },
          "page_heading": {
            "type": "string",
            "nullable": true
          },
          "welcome_message": {
            "type": "string",
            "nullable": true
          },
          "show_welcome_message": {
            "type": "boolean"
          },
          "notify_emails": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "public_url": {
            "type": "string",
            "examples": [
              "/submit/ai-engineer/ai-summit-2026/cfp"
            ],
            "description": "The canonical link an organizer shares."
          },
          "questions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FormQuestion"
            }
          },
          "participant_config": {
            "type": "object",
            "properties": {
              "speaker_min": {
                "type": "integer"
              },
              "speaker_max": {
                "type": "integer"
              },
              "chairperson_enabled": {
                "type": "boolean"
              },
              "moderator_enabled": {
                "type": "boolean"
              },
              "send_confirmation_email": {
                "type": "boolean"
              },
              "fields": {
                "type": "array",
                "items": {
                  "type": "object",
                  "properties": {
                    "id": {
                      "type": "string"
                    },
                    "internal_name": {
                      "type": "string",
                      "examples": [
                        "participant.email"
                      ]
                    },
                    "label": {
                      "type": "string"
                    },
                    "required": {
                      "type": "boolean"
                    },
                    "enabled": {
                      "type": "boolean"
                    },
                    "locked": {
                      "type": "boolean"
                    },
                    "help": {
                      "type": "string",
                      "nullable": true
                    }
                  }
                }
              }
            }
          },
          "settings": {
            "type": "object",
            "properties": {
              "limit_per_user": {
                "type": "integer",
                "nullable": true
              },
              "allow_drafts": {
                "type": "boolean"
              },
              "success_message": {
                "type": "string",
                "nullable": true
              },
              "auto_redirect_to_portal": {
                "type": "boolean"
              },
              "send_reminder_email": {
                "type": "boolean"
              }
            }
          },
          "submission_count": {
            "type": "integer"
          },
          "draft_count": {
            "type": "integer"
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Creation time."
          },
          "updated_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Last change."
          }
        }
      },
      "FormQuestion": {
        "type": "object",
        "description": "One question on the form — the same object as a custom-field definition. `id`/`internal_name` is the key its answers are stored under.",
        "properties": {
          "id": {
            "type": "string",
            "examples": [
              "format"
            ]
          },
          "internal_name": {
            "type": "string",
            "examples": [
              "format"
            ]
          },
          "public_name": {
            "type": "string",
            "examples": [
              "Format"
            ]
          },
          "label": {
            "type": "string",
            "examples": [
              "Format"
            ]
          },
          "field_type": {
            "type": "string",
            "examples": [
              "dropdown"
            ]
          },
          "type": {
            "type": "string",
            "examples": [
              "dropdown"
            ]
          },
          "required": {
            "type": "boolean"
          },
          "enabled": {
            "type": "boolean"
          },
          "locked": {
            "type": "boolean",
            "description": "System questions the public flow depends on; they cannot be removed."
          },
          "help": {
            "type": "string",
            "nullable": true
          },
          "placeholder": {
            "type": "string",
            "nullable": true
          },
          "options": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "max_chars": {
            "type": "integer",
            "nullable": true
          },
          "show_if": {
            "type": "object",
            "nullable": true,
            "description": "Conditional logic — show this question only when another answered a value.",
            "properties": {
              "questionId": {
                "type": "string"
              },
              "equals": {
                "type": "string"
              }
            }
          },
          "is_track_question": {
            "type": "boolean",
            "description": "The answer to this question routes the submission to a track."
          },
          "order": {
            "type": "integer"
          }
        }
      },
      "Task": {
        "type": "object",
        "description": "One thing a speaker owes the organizer.",
        "properties": {
          "id": {
            "type": "string"
          },
          "title": {
            "type": "string",
            "examples": [
              "Upload your slides"
            ]
          },
          "instructions": {
            "type": "string",
            "nullable": true
          },
          "kind": {
            "type": "string",
            "enum": [
              "profile",
              "headshot",
              "upload",
              "answer",
              "confirm"
            ],
            "description": "How it gets ticked off. `answer` asks a question in `instructions` and the speaker types a reply."
          },
          "response": {
            "type": "string",
            "nullable": true,
            "description": "Kind `answer` only: what the speaker wrote back."
          },
          "due_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Deadline."
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the speaker ticked it off."
          },
          "is_complete": {
            "type": "boolean"
          },
          "is_overdue": {
            "type": "boolean"
          },
          "speaker_id": {
            "type": "string"
          },
          "speaker": {
            "type": "object",
            "nullable": true,
            "properties": {
              "id": {
                "type": "string"
              },
              "full_name": {
                "type": "string"
              },
              "email": {
                "type": "string"
              }
            }
          },
          "session_id": {
            "type": "string",
            "nullable": true
          },
          "session_title": {
            "type": "string",
            "nullable": true
          },
          "form_id": {
            "type": "string",
            "nullable": true
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Creation time."
          }
        }
      },
      "EvaluationCriterion": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "label": {
            "type": "string",
            "examples": [
              "Relevance"
            ]
          },
          "type": {
            "type": "string",
            "enum": [
              "numeric",
              "select",
              "text"
            ]
          },
          "options": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "nullable": true
          },
          "weight": {
            "type": "number",
            "description": "Relative importance in the weighted average. Numeric criteria only."
          }
        }
      },
      "EvaluationPlan": {
        "type": "object",
        "description": "One review round: criteria, a pool of submissions, and evaluators.",
        "properties": {
          "id": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "examples": [
              "Round 1 — technical review"
            ]
          },
          "round": {
            "type": "integer"
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "closed"
            ]
          },
          "blind": {
            "type": "boolean",
            "description": "Evaluators see the submissions without speaker identities."
          },
          "opens_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the round opens."
          },
          "due_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When the round closes."
          },
          "criteria": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EvaluationCriterion"
            }
          },
          "submission_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "submission_count": {
            "type": "integer"
          },
          "evaluator_count": {
            "type": "integer"
          },
          "assigned_count": {
            "type": "integer",
            "description": "Evaluations expected in total."
          },
          "completed_count": {
            "type": "integer"
          },
          "outstanding_count": {
            "type": "integer"
          },
          "completion_pct": {
            "type": "integer"
          },
          "recused_count": {
            "type": "integer"
          },
          "scored_count": {
            "type": "integer"
          },
          "average_score": {
            "type": "number",
            "nullable": true,
            "description": "Weighted mean over numeric criteria. Recusals never reach it."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Creation time."
          },
          "evaluators": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Evaluator"
            },
            "description": "Only on the detail read."
          },
          "submissions": {
            "type": "array",
            "description": "Only on the detail read — the pool with per-submission averages.",
            "items": {
              "type": "object",
              "properties": {
                "id": {
                  "type": "string"
                },
                "title": {
                  "type": "string"
                },
                "status": {
                  "type": "string"
                },
                "completed_count": {
                  "type": "integer"
                },
                "recused_count": {
                  "type": "integer"
                },
                "average_score": {
                  "type": "number",
                  "nullable": true
                }
              }
            }
          }
        }
      },
      "Evaluator": {
        "type": "object",
        "properties": {
          "id": {
            "type": "string"
          },
          "plan_id": {
            "type": "string"
          },
          "plan_name": {
            "type": "string",
            "description": "Only on the event-wide list."
          },
          "plan_round": {
            "type": "integer",
            "description": "Only on the event-wide list."
          },
          "email": {
            "type": "string"
          },
          "name": {
            "type": "string",
            "nullable": true
          },
          "token": {
            "type": "string",
            "description": "Their magic review link's token. Organizer-only — never publish it."
          },
          "review_path": {
            "type": "string",
            "examples": [
              "/review/6f2c…"
            ]
          },
          "assigned_submission_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "custom_assignment": {
            "type": "boolean",
            "description": "True when the queue was hand-picked rather than the whole pool."
          },
          "completed_count": {
            "type": "integer"
          },
          "assigned_count": {
            "type": "integer"
          },
          "outstanding_count": {
            "type": "integer"
          },
          "recused_count": {
            "type": "integer"
          },
          "last_reminded_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Last nudge."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Creation time."
          }
        }
      },
      "Evaluation": {
        "type": "object",
        "description": "One evaluator's scorecard for one submission.",
        "properties": {
          "id": {
            "type": "string"
          },
          "plan_id": {
            "type": "string"
          },
          "plan_name": {
            "type": "string"
          },
          "round": {
            "type": "integer"
          },
          "session_id": {
            "type": "string"
          },
          "session_title": {
            "type": "string",
            "nullable": true
          },
          "evaluator_id": {
            "type": "string"
          },
          "evaluator_email": {
            "type": "string",
            "nullable": true
          },
          "scores": {
            "type": "object",
            "additionalProperties": {
              "type": "number"
            },
            "description": "criterion id → 1–5. Numeric criteria only."
          },
          "values": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "criterion id → chosen option or free text."
          },
          "comment": {
            "type": "string",
            "nullable": true
          },
          "recused": {
            "type": "boolean"
          },
          "recusal_reason": {
            "type": "string",
            "nullable": true
          },
          "completed_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "When it was submitted."
          },
          "created_at": {
            "type": "string",
            "format": "date-time",
            "nullable": true,
            "description": "Creation time."
          }
        }
      },
      "EventWriteBody": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "examples": [
              "AI Summit 2026"
            ]
          },
          "slug": {
            "type": "string",
            "description": "The public address. Derived from the name when omitted; suffixed rather than rejected if taken."
          },
          "timezone": {
            "type": "string",
            "examples": [
              "America/Los_Angeles"
            ],
            "default": "UTC"
          },
          "type": {
            "type": "string",
            "examples": [
              "Conference"
            ]
          },
          "website_url": {
            "type": "string"
          },
          "description": {
            "type": "string"
          },
          "venue": {
            "type": "string"
          },
          "starts_at": {
            "type": "string",
            "description": "ISO-8601 or epoch milliseconds.",
            "examples": [
              "2026-09-14T09:00:00.000Z"
            ]
          },
          "ends_at": {
            "type": "string",
            "description": "ISO-8601 or epoch milliseconds."
          },
          "organization_id": {
            "type": "string",
            "description": "Workspace to create the event in. Optional when you administer exactly one — otherwise the 400 lists your choices."
          },
          "portal_settings": {
            "type": "object",
            "description": "Speaker-portal behaviour. Unspecified flags keep their current value.",
            "properties": {
              "always_show_tasks": {
                "type": "boolean"
              },
              "allow_submission_edits": {
                "type": "boolean"
              },
              "extend_task_deadlines": {
                "type": "boolean"
              }
            }
          }
        }
      },
      "ParticipantWriteBody": {
        "type": "object",
        "description": "Name an existing person with `speaker_id`, or an `email` — a person this event has never seen is created, which needs `first_name`.",
        "properties": {
          "speaker_id": {
            "type": "string"
          },
          "email": {
            "type": "string",
            "format": "email"
          },
          "first_name": {
            "type": "string"
          },
          "last_name": {
            "type": "string"
          },
          "role": {
            "type": "string",
            "enum": [
              "speaker",
              "chairperson",
              "moderator"
            ],
            "default": "speaker"
          }
        }
      },
      "FormWriteBody": {
        "type": "object",
        "properties": {
          "internal_name": {
            "type": "string",
            "description": "Required on create."
          },
          "external_title": {
            "type": "string",
            "description": "What the public form is titled."
          },
          "kind": {
            "type": "string",
            "enum": [
              "abstract",
              "session"
            ],
            "default": "abstract"
          },
          "slug": {
            "type": "string",
            "description": "Public address inside the event."
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "closed"
            ]
          },
          "close_at": {
            "type": "string",
            "description": "ISO-8601 or epoch milliseconds."
          },
          "page_heading": {
            "type": "string"
          },
          "welcome_message": {
            "type": "string"
          },
          "show_welcome_message": {
            "type": "boolean"
          },
          "notify_emails": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Who gets told when a submission arrives."
          },
          "questions": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FormQuestion"
            },
            "description": "Replaces the question set wholesale. Locked system questions must be included."
          },
          "participant_config": {
            "type": "object",
            "properties": {
              "speaker_min": {
                "type": "integer"
              },
              "speaker_max": {
                "type": "integer"
              },
              "chairperson_enabled": {
                "type": "boolean"
              },
              "moderator_enabled": {
                "type": "boolean"
              },
              "send_confirmation_email": {
                "type": "boolean"
              },
              "fields": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": true
                }
              }
            }
          },
          "settings": {
            "type": "object",
            "properties": {
              "limit_per_user": {
                "type": "integer"
              },
              "allow_drafts": {
                "type": "boolean"
              },
              "success_message": {
                "type": "string"
              },
              "auto_redirect_to_portal": {
                "type": "boolean"
              },
              "send_reminder_email": {
                "type": "boolean"
              }
            }
          }
        }
      },
      "TaskWriteBody": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string",
            "examples": [
              "Upload your slides"
            ]
          },
          "instructions": {
            "type": "string"
          },
          "kind": {
            "type": "string",
            "enum": [
              "profile",
              "headshot",
              "upload",
              "answer",
              "confirm"
            ],
            "default": "upload"
          },
          "due_at": {
            "type": "string",
            "description": "ISO-8601 or epoch milliseconds."
          },
          "completed": {
            "type": "boolean",
            "description": "Update only — tick the task off (or reopen it) on the speaker's behalf."
          },
          "session_id": {
            "type": "string",
            "description": "Bind the task to a session, so files uploaded into it land on that session."
          },
          "speaker_ids": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "speaker_emails": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Assign by address without looking ids up first."
          }
        }
      },
      "EvaluationPlanWriteBody": {
        "type": "object",
        "properties": {
          "name": {
            "type": "string",
            "description": "Required on create."
          },
          "round": {
            "type": "integer",
            "default": 1
          },
          "status": {
            "type": "string",
            "enum": [
              "open",
              "closed"
            ]
          },
          "blind": {
            "type": "boolean"
          },
          "opens_at": {
            "type": "string",
            "description": "ISO-8601 or epoch milliseconds."
          },
          "due_at": {
            "type": "string",
            "description": "ISO-8601 or epoch milliseconds."
          },
          "submission_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The pool. Replaces the current pool wholesale."
          },
          "criteria": {
            "type": "array",
            "description": "At least one is required on create. Replaces the criteria wholesale.",
            "items": {
              "type": "object",
              "required": [
                "label"
              ],
              "properties": {
                "id": {
                  "type": "string",
                  "description": "Derived from the label when omitted."
                },
                "label": {
                  "type": "string"
                },
                "type": {
                  "type": "string",
                  "enum": [
                    "numeric",
                    "select",
                    "text"
                  ],
                  "default": "numeric"
                },
                "options": {
                  "type": "array",
                  "items": {
                    "type": "string"
                  }
                },
                "weight": {
                  "type": "number",
                  "default": 1
                }
              }
            }
          }
        }
      },
      "EvaluatorWriteBody": {
        "type": "object",
        "properties": {
          "plan_id": {
            "type": "string",
            "description": "Required on create."
          },
          "email": {
            "type": "string",
            "format": "email",
            "description": "Required on create."
          },
          "name": {
            "type": "string"
          },
          "assigned_submission_ids": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Hand-picked queue. Must be a subset of the plan's pool. Omit for the whole pool."
          }
        }
      },
      "WebhookWriteBody": {
        "type": "object",
        "properties": {
          "url": {
            "type": "string",
            "format": "uri"
          },
          "events": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "Event types to subscribe to; `[\"*\"]` means all."
          },
          "description": {
            "type": "string"
          },
          "enabled": {
            "type": "boolean"
          },
          "event": {
            "type": "string",
            "description": "Event slug or id to scope the endpoint to. Omit for a workspace-wide endpoint."
          }
        }
      },
      "SessionFileCreateBody": {
        "type": "object",
        "required": [
          "filename"
        ],
        "properties": {
          "filename": {
            "type": "string",
            "examples": [
              "keynote-slides.pptx"
            ]
          },
          "size_bytes": {
            "type": "integer",
            "minimum": 1
          },
          "content_type": {
            "type": "string"
          },
          "mimetype": {
            "type": "string",
            "description": "Alias of `content_type`."
          },
          "title": {
            "type": "string"
          },
          "assigned_participant_id": {
            "type": "string",
            "nullable": true
          }
        }
      },
      "SessionFileUpdateBody": {
        "type": "object",
        "properties": {
          "title": {
            "type": "string"
          },
          "assigned_participant_id": {
            "type": "string",
            "nullable": true,
            "description": "Empty string clears the assignment."
          }
        }
      },
      "SessionFileUploadForm": {
        "type": "object",
        "required": [
          "file"
        ],
        "properties": {
          "file": {
            "type": "string",
            "format": "binary"
          },
          "title": {
            "type": "string"
          },
          "assigned_participant_id": {
            "type": "string"
          }
        }
      },
      "FileUploadTicket": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "id": {
                "type": "string"
              },
              "filename": {
                "type": "string"
              },
              "title": {
                "type": "string"
              },
              "replaces": {
                "type": "string"
              },
              "upload": {
                "type": "object",
                "properties": {
                  "url": {
                    "type": "string",
                    "format": "uri"
                  },
                  "method": {
                    "type": "string",
                    "examples": [
                      "PUT"
                    ]
                  },
                  "headers": {
                    "type": "object",
                    "additionalProperties": {
                      "type": "string"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "SessionEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Session"
          }
        },
        "required": [
          "data"
        ],
        "description": "Single-resource envelope. The resource is under `data`."
      },
      "SpeakerEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Speaker"
          }
        },
        "required": [
          "data"
        ],
        "description": "Single-resource envelope. The resource is under `data`."
      },
      "EventEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Event"
          }
        },
        "required": [
          "data"
        ],
        "description": "Single-resource envelope. The resource is under `data`."
      },
      "FieldEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Field"
          }
        },
        "required": [
          "data"
        ],
        "description": "Single-resource envelope. The resource is under `data`."
      },
      "MetadataEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/NamedMetadata"
          }
        },
        "required": [
          "data"
        ],
        "description": "Single-resource envelope. The resource is under `data`."
      },
      "FileEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/SessionFile"
          }
        },
        "required": [
          "data"
        ],
        "description": "Single-resource envelope. The resource is under `data`."
      },
      "AgendaEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Agenda"
          }
        },
        "required": [
          "data"
        ],
        "description": "Single-resource envelope. The resource is under `data`."
      },
      "WebhookEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Webhook"
          }
        },
        "required": [
          "data"
        ],
        "description": "Single-resource envelope. The resource is under `data`."
      },
      "WebhookDetailEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Webhook"
              },
              {
                "type": "object",
                "properties": {
                  "deliveries": {
                    "type": "array",
                    "items": {
                      "$ref": "#/components/schemas/WebhookDelivery"
                    }
                  }
                }
              }
            ]
          }
        },
        "required": [
          "data"
        ],
        "description": "Single-resource envelope. The resource is under `data`."
      },
      "WebhookTestEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "type": "object",
            "properties": {
              "delivery_id": {
                "type": "string"
              },
              "status": {
                "type": "string",
                "examples": [
                  "queued"
                ]
              }
            }
          }
        },
        "required": [
          "data"
        ],
        "description": "Single-resource envelope. The resource is under `data`."
      },
      "FileListEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SessionFile"
            }
          }
        }
      },
      "WebhookListEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Webhook"
            }
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Webhook"
            }
          }
        }
      },
      "WebhookDeliveryListEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookDelivery"
            }
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/WebhookDelivery"
            }
          }
        }
      },
      "EventDetailEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Event"
              },
              {
                "type": "object",
                "properties": {
                  "totals": {
                    "type": "object",
                    "description": "Row counts for the event, so one call answers “did my import land?”.",
                    "properties": {
                      "rooms": {
                        "type": "integer"
                      },
                      "tracks": {
                        "type": "integer"
                      },
                      "forms": {
                        "type": "integer"
                      },
                      "sessions": {
                        "type": "integer"
                      },
                      "abstracts": {
                        "type": "integer"
                      },
                      "accepted": {
                        "type": "integer"
                      },
                      "scheduled": {
                        "type": "integer"
                      }
                    }
                  }
                }
              }
            ]
          }
        },
        "required": [
          "data"
        ],
        "description": "Single-resource envelope. The resource is under `data`."
      },
      "FormEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Form"
          }
        },
        "required": [
          "data"
        ],
        "description": "Single-resource envelope. The resource is under `data`."
      },
      "TaskEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Task"
          }
        },
        "required": [
          "data"
        ],
        "description": "Single-resource envelope. The resource is under `data`."
      },
      "TaskCreateEnvelope": {
        "type": "object",
        "description": "One task row per speaker. `data` is the first (the single-speaker case); `results` is all of them.",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Task"
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Task"
            }
          },
          "created": {
            "type": "integer"
          }
        }
      },
      "EvaluationPlanEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/EvaluationPlan"
          }
        },
        "required": [
          "data"
        ],
        "description": "Single-resource envelope. The resource is under `data`."
      },
      "EvaluatorEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/Evaluator"
          }
        },
        "required": [
          "data"
        ],
        "description": "Single-resource envelope. The resource is under `data`."
      },
      "StatusEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "$ref": "#/components/schemas/SessionStatus"
          }
        },
        "required": [
          "data"
        ],
        "description": "Single-resource envelope. The resource is under `data`."
      },
      "ParticipantEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "allOf": [
              {
                "$ref": "#/components/schemas/Speaker"
              },
              {
                "type": "object",
                "properties": {
                  "participant_id": {
                    "type": "string"
                  },
                  "role": {
                    "type": "string",
                    "enum": [
                      "speaker",
                      "chairperson",
                      "moderator"
                    ]
                  },
                  "session_id": {
                    "type": "string"
                  }
                }
              }
            ]
          }
        },
        "required": [
          "data"
        ],
        "description": "Single-resource envelope. The resource is under `data`."
      },
      "ParticipantListEnvelope": {
        "type": "object",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Speaker"
            }
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Speaker"
            }
          }
        }
      },
      "FormsPage": {
        "type": "object",
        "description": "Paginated envelope. `data` and `results` are the same array — `data` is what this API has always returned, `results` is what Sessionboard's search endpoints return.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Form"
            }
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Form"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "TasksPage": {
        "type": "object",
        "description": "Paginated envelope. `data` and `results` are the same array — `data` is what this API has always returned, `results` is what Sessionboard's search endpoints return.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Task"
            }
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Task"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "EvaluationPlansPage": {
        "type": "object",
        "description": "Paginated envelope. `data` and `results` are the same array — `data` is what this API has always returned, `results` is what Sessionboard's search endpoints return.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EvaluationPlan"
            }
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/EvaluationPlan"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "EvaluatorsPage": {
        "type": "object",
        "description": "Paginated envelope. `data` and `results` are the same array — `data` is what this API has always returned, `results` is what Sessionboard's search endpoints return.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Evaluator"
            }
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Evaluator"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "EvaluationsPage": {
        "type": "object",
        "description": "Paginated envelope. `data` and `results` are the same array — `data` is what this API has always returned, `results` is what Sessionboard's search endpoints return.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Evaluation"
            }
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Evaluation"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "StatusesPage": {
        "type": "object",
        "description": "Paginated envelope. `data` and `results` are the same array — `data` is what this API has always returned, `results` is what Sessionboard's search endpoints return.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SessionStatus"
            }
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SessionStatus"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "SessionsPage": {
        "type": "object",
        "description": "Paginated envelope. `data` and `results` are the same array — `data` is what this API has always returned, `results` is what Sessionboard's search endpoints return.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Session"
            }
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Session"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          },
          "event": {
            "$ref": "#/components/schemas/Event"
          }
        }
      },
      "SessionStatusesPage": {
        "type": "object",
        "description": "Paginated envelope. `data` and `results` are the same array — `data` is what this API has always returned, `results` is what Sessionboard's search endpoints return.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SessionStatusRow"
            }
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/SessionStatusRow"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "SpeakersPage": {
        "type": "object",
        "description": "Paginated envelope. `data` and `results` are the same array — `data` is what this API has always returned, `results` is what Sessionboard's search endpoints return.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Speaker"
            }
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Speaker"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          },
          "event": {
            "$ref": "#/components/schemas/Event"
          }
        }
      },
      "SubmissionsPage": {
        "type": "object",
        "description": "Paginated envelope. `data` and `results` are the same array — `data` is what this API has always returned, `results` is what Sessionboard's search endpoints return.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Submission"
            }
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Submission"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          },
          "event": {
            "$ref": "#/components/schemas/Event"
          }
        }
      },
      "EventsPage": {
        "type": "object",
        "description": "Paginated envelope. `data` and `results` are the same array — `data` is what this API has always returned, `results` is what Sessionboard's search endpoints return.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Event"
            }
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Event"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "FieldsPage": {
        "type": "object",
        "description": "Paginated envelope. `data` and `results` are the same array — `data` is what this API has always returned, `results` is what Sessionboard's search endpoints return.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Field"
            }
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Field"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      },
      "MetadataPage": {
        "type": "object",
        "description": "Paginated envelope. `data` and `results` are the same array — `data` is what this API has always returned, `results` is what Sessionboard's search endpoints return.",
        "properties": {
          "data": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NamedMetadata"
            }
          },
          "results": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/NamedMetadata"
            }
          },
          "pagination": {
            "$ref": "#/components/schemas/Pagination"
          }
        }
      }
    }
  }
}
