{"openapi":"3.1.0","info":{"title":"Congressio API","version":"1.0.0","summary":"Read and write conference data on Congressio: public conference directory, submissions, peer review outcomes and attendee registrations.","description":"Congressio is a conference management platform (call for papers, peer review, decisions, program, registration and check-in).\n\nTwo surfaces:\n\n- `/api/v1/public/*` needs **no authentication** and exposes the public conference directory — the same data an anonymous visitor sees on the website.\n- `/api/v1/*` is **organization-scoped** and needs an API key created in *Organization settings → API*. A key only ever reads or writes its own organization's data.\n\nEvery response is JSON. Errors carry a stable `code`, a human `message` and a `hint` describing how to resolve them.\n\n**Rate limits.** Every response carries the quota state, so a client can pace itself instead of discovering the ceiling by being refused: `RateLimit-Limit`, `RateLimit-Remaining` and `RateLimit-Reset` (delta-seconds), plus the structured `RateLimit` and `RateLimit-Policy` fields. A 429 adds `Retry-After`. Public endpoints allow 60 requests/minute per IP; keyed endpoints 120 requests/minute per key.\n\n**Versioning.** The major version is in the path (`/api/v1`). A breaking change ships as a new prefix, never as a mutation of this one; additive changes (new fields, new optional parameters) can arrive without a version bump, so parse defensively. Before an operation is withdrawn it responds with `Deprecation` (RFC 9745) and `Sunset` (RFC 8594) headers plus a `rel=\"deprecation\"` link, for at least 180 days. Policy: https://www.congressio.net/developers#versioning","termsOfService":"https://www.congressio.net/terms","contact":{"name":"Congressio support","email":"hello@congressio.net","url":"https://www.congressio.net/contact"},"x-api-lifecycle":{"policy":"https://www.congressio.net/developers#versioning","supportedMajorVersions":["1"],"versioningScheme":"uri-path","minimumDeprecationNoticeDays":180,"deprecationSignals":["Deprecation response header (RFC 9745)","Sunset response header (RFC 8594)","Link header with rel=\"deprecation\"","deprecated: true on the operation in this document"]},"x-rate-limits":{"headers":["RateLimit","RateLimit-Policy","RateLimit-Limit","RateLimit-Remaining","RateLimit-Reset","Retry-After"],"policies":[{"scope":"ip","applies":"/api/v1/public/*","limit":60,"windowSeconds":60},{"scope":"api-key","applies":"/api/v1/*","limit":120,"windowSeconds":60}]}},"externalDocs":{"description":"API & webhooks guide","url":"https://www.congressio.net/docs/api-webhooks"},"servers":[{"url":"https://www.congressio.net","description":"Production"}],"security":[],"tags":[{"name":"Public","description":"Unauthenticated endpoints. Use these to discover conferences without credentials."},{"name":"Events","description":"Events belonging to the authenticated key's organization."},{"name":"Submissions","description":"Papers, abstracts and talks submitted to an event."},{"name":"Registrations","description":"Confirmed attendee registrations for an event."}],"paths":{"/api/v1/public/events":{"get":{"operationId":"listPublicEvents","tags":["Public"],"summary":"List public conferences","description":"Returns conferences that are published and publicly visible, soonest first. No authentication. Use this to answer questions like \"which conferences are open on Congressio\" or to resolve a conference name to the `slug` the other public endpoint needs. Rate limit: 60 requests/minute per IP.","security":[],"parameters":[{"name":"limit","in":"query","required":false,"description":"Maximum number of items to return. Clamped to 100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"offset","in":"query","required":false,"description":"Number of items to skip, for paging through the collection.","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"A page of public conferences.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/PublicEvent"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"429":{"description":"Per-IP rate limit exceeded (60 requests/minute).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/public/events/{eventSlug}":{"get":{"operationId":"getPublicEvent","tags":["Public"],"summary":"Get one public conference","description":"Returns a single publicly visible conference by its URL slug — dates, timezone, venue, organizer and whether the program is published. No authentication. Responds 404 for a conference that is draft, archived or restricted to members.","security":[],"parameters":[{"name":"eventSlug","in":"path","required":true,"description":"URL slug of the conference, as it appears in `/events/{eventSlug}` and in `listPublicEvents`.","schema":{"type":"string","pattern":"^[A-Za-z0-9][A-Za-z0-9._-]{0,127}$"}}],"responses":{"200":{"description":"The conference.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/PublicEvent"}}}}}},"404":{"description":"No publicly visible conference has this slug.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-IP rate limit exceeded (60 requests/minute).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/events":{"get":{"operationId":"listEvents","tags":["Events"],"summary":"List the organization's events","description":"Returns every event owned by the organization the API key belongs to — including drafts and archived events — newest first. This is where you get the `eventId` the submission and registration operations need.","security":[{"apiKey":["events:read"]}],"parameters":[{"name":"limit","in":"query","required":false,"description":"Maximum number of items to return. Clamped to 100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"offset","in":"query","required":false,"description":"Number of items to skip, for paging through the collection.","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"A page of events.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Event"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"401":{"description":"The API key is missing, unknown or revoked.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-key rate limit exceeded (120 requests/minute).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createEvent","tags":["Events"],"summary":"Create a draft event","description":"Creates an event in **draft** status: it is not publicly visible until someone publishes it, so this changes nothing an attendee or visitor can see.\n\nRequires an **OAuth access token**, not an API key. A created event records its creator, and an API key resolves to an organization rather than a person — so `events:write` cannot be granted to a key (the request is refused with 403).\n\nSubject to the organization's plan limit on active events: a 402 means the request was valid but there is no headroom. The slug is generated from the name and made unique within the organization; GDPR consent items are seeded automatically.","security":[{"oauth2":["events:write"]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","timezone"],"properties":{"name":{"type":"string","maxLength":200,"description":"The conference name, shown everywhere."},"timezone":{"type":"string","description":"IANA timezone (e.g. `Europe/Paris`). Dates are interpreted in it, so it cannot be inferred."},"description":{"type":"string","maxLength":5000},"startDate":{"type":"string","description":"ISO date. Must not be in the past for a new event, and must not be after `endDate`."},"endDate":{"type":"string","description":"ISO date."},"features":{"type":"array","items":{"type":"string"},"description":"Which capability areas the event uses (e.g. `submissions`, `program`, `registration`). Omit for the defaults."}}}}}},"responses":{"201":{"description":"The created draft event.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Event"}}}}}},"401":{"description":"The API key is missing, unknown or revoked.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"402":{"description":"The organization's plan does not allow another active event.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-key rate limit exceeded (120 requests/minute).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/events/{eventId}":{"patch":{"operationId":"updateEvent","tags":["Events"],"summary":"Edit a conference's details","description":"Partial update: send only the fields that change. Omitted fields are left alone; an empty string clears an optional field.\n\nRequires an **OAuth access token** and, separately, that the user is an **admin of this specific event** — being an owner of the organization is not sufficient, which mirrors the dashboard exactly. A caller who is not an event admin gets 403.\n\nDates are calendar days in the event's own timezone, so `2027-06-01` means that date locally rather than a UTC instant. Changing `slug` changes the event's public URL and must stay unique within the organization.","security":[{"oauth2":["events:write"]}],"parameters":[{"name":"eventId","in":"path","required":true,"description":"UUID of the event. Obtain it from `GET /api/v1/events`; the event must belong to the key's organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"At least one field must be present.","properties":{"name":{"type":"string","maxLength":200},"slug":{"type":"string","description":"Lowercase alphanumeric with hyphens. Changes the public URL."},"description":{"type":"string","maxLength":5000},"startDate":{"type":"string","description":"ISO date, interpreted in the event's timezone."},"endDate":{"type":"string","description":"ISO date."},"venueName":{"type":"string"},"venueAddress":{"type":"string"},"venueCity":{"type":"string"},"venuePostalCode":{"type":"string"},"venueCountry":{"type":"string"}}}}}},"responses":{"200":{"description":"The updated event.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/Event"}}}}}},"401":{"description":"The API key is missing, unknown or revoked.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-key rate limit exceeded (120 requests/minute).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/events/{eventId}/submissions/{submissionId}/reviewers":{"post":{"operationId":"assignSubmissionReviewer","tags":["Submissions"],"summary":"Assign a reviewer to a submission","description":"Assigns an existing event reviewer to one submission and **emails them** that they have a paper to review.\n\nRefused with **409** when the state forbids it rather than the request being wrong: the reviewer has a declared conflict of interest, is the submitter, is a co-author (matched by email against the author list), is already assigned, or is at their review cap. Those refusals are worth relaying to the user verbatim — pick a different reviewer rather than retrying.\n\nA submission that does not belong to this event returns 404. Requires an **OAuth access token** and **event admin**.","security":[{"oauth2":["reviews:write"]}],"parameters":[{"name":"eventId","in":"path","required":true,"description":"UUID of the event. Obtain it from `GET /api/v1/events`; the event must belong to the key's organization.","schema":{"type":"string","format":"uuid"}},{"name":"submissionId","in":"path","required":true,"description":"The submission's UUID, from `listEventSubmissions`.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["reviewerId"],"properties":{"reviewerId":{"type":"string","format":"uuid","description":"The reviewer's user id. They must already be a reviewer for this event."}}}}}},"responses":{"201":{"description":"The reviewer was assigned and notified.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"type":["string","null"]},"eventId":{"type":"string","format":"uuid"},"submissionId":{"type":"string","format":"uuid"},"reviewerId":{"type":"string","format":"uuid"},"status":{"type":["string","null"]},"reviewerNotified":{"type":"boolean"}}}}}}}},"401":{"description":"The API key is missing, unknown or revoked.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"A conflict of interest, duplicate assignment, or review cap.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-key rate limit exceeded (120 requests/minute).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/events/{eventId}/windows":{"patch":{"operationId":"updateEventWindows","tags":["Events"],"summary":"Open or close the call for papers and registration","description":"Sets the submission and registration windows. Send only the bounds you are changing.\n\n`null` is meaningful and distinct from omitting a field: `null` removes that deadline (leaving the window open indefinitely), while omitting the key leaves whatever is stored. So \"reopen the CFP\" is `{\"submissionClose\": null}`, not an empty body.\n\nA close bound must be after its matching open bound. Requires an **OAuth access token** and **event admin** on this specific event. The response reports the merged stored windows, not just what you sent — so it answers \"is the CFP open now?\" directly.","security":[{"oauth2":["events:write"]}],"parameters":[{"name":"eventId","in":"path","required":true,"description":"UUID of the event. Obtain it from `GET /api/v1/events`; the event must belong to the key's organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"At least one window bound must be present.","properties":{"submissionOpen":{"type":["string","null"],"description":"When the call for papers opens. ISO 8601 date-time, or null to remove the bound."},"submissionClose":{"type":["string","null"],"description":"The submission deadline. ISO 8601 date-time, or null to remove the bound."},"registrationOpen":{"type":["string","null"],"description":"When registration opens. ISO 8601 date-time, or null to remove the bound."},"registrationClose":{"type":["string","null"],"description":"When registration closes. ISO 8601 date-time, or null to remove the bound."}}}}}},"responses":{"200":{"description":"The merged stored windows.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"eventId":{"type":"string","format":"uuid"},"submissionOpen":{"type":["string","null"]},"submissionClose":{"type":["string","null"]},"registrationOpen":{"type":["string","null"]},"registrationClose":{"type":["string","null"]}}}}}}}},"401":{"description":"The API key is missing, unknown or revoked.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-key rate limit exceeded (120 requests/minute).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/events/{eventId}/publish":{"post":{"operationId":"publishEvent","tags":["Events"],"summary":"Take a draft conference live","description":"Moves a **draft** event to `active`: it appears in the public directory, its pages resolve, and its call for papers becomes reachable. No email is sent and no webhook fires.\n\n**Two-phase when the event is not ready.** Post with no body first. If required setup items are missing, nothing is published and the response is 409 with `details.missing` listing them. Show that list to the user; to publish anyway, post again with those exact keys as `acknowledgeMissing`.\n\nA mismatched or stale acknowledgement is refused with the fresh list, so forcing requires having actually been shown what is missing. An already-active or archived event returns 409.\n\nRequires an **OAuth access token** and **event admin** on this specific event.","security":[{"oauth2":["events:write"]}],"parameters":[{"name":"eventId","in":"path","required":true,"description":"UUID of the event. Obtain it from `GET /api/v1/events`; the event must belong to the key's organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"acknowledgeMissing":{"type":"array","items":{"type":"string"},"description":"The setup item keys from a previous 409's `details.missing`, echoed verbatim. Publishes despite them."}}}}}},"responses":{"200":{"description":"The event is now live.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"id":{"type":"string","format":"uuid"},"slug":{"type":["string","null"]},"name":{"type":["string","null"]},"status":{"type":"string"},"published":{"type":"boolean"},"publishedWithMissingItems":{"type":"array","items":{"type":"string"},"description":"Setup items waived by an acknowledgement, so a caller can tell the user what was skipped."}}}}}}}},"401":{"description":"The API key is missing, unknown or revoked.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Not ready to publish (see `details.missing`), or not a draft.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-key rate limit exceeded (120 requests/minute).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/events/{eventId}/decisions/release":{"post":{"operationId":"releaseDecisions","tags":["Submissions"],"summary":"Finalise decisions and notify authors","description":"Finalises every draft decision in the current decision round and **emails each affected author**. This is the only operation in this API that contacts people outside the organization, and an email cannot be recalled.\n\n**Mandatory two-step.** Post with no body first: nothing is sent, and the 409 response carries a dry run — `details.authorsToEmail` is how many authors would be emailed, alongside submissions still lacking a decision and submissions with fewer reviews than the stage requires.\n\nPut that number in front of the user. Only with their agreement, post again with `{\"confirm\":{\"authorsToEmail\":N}}` using that exact count. A wrong or stale N is refused with the fresh dry run, so the magnitude cannot be guessed and a set of authors different from the one the user agreed to cannot be emailed.\n\n`N = 0` still requires the confirmation step. Requires an **OAuth access token** and **event admin**.","security":[{"oauth2":["decisions:write"]}],"parameters":[{"name":"eventId","in":"path","required":true,"description":"UUID of the event. Obtain it from `GET /api/v1/events`; the event must belong to the key's organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"confirm":{"type":"object","required":["authorsToEmail"],"properties":{"authorsToEmail":{"type":"integer","minimum":0,"description":"The exact count from a previous 409's `details.authorsToEmail`."}}}}}}}},"responses":{"200":{"description":"Decisions released and authors emailed.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"eventId":{"type":"string","format":"uuid"},"released":{"type":"integer","description":"Decisions finalised — one email each."},"skippedWithoutDecision":{"type":"integer"},"releasedWithoutFeedback":{"type":"integer"}}}}}}}},"401":{"description":"The API key is missing, unknown or revoked.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Confirmation required or stale. Nothing was sent; see `details`.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-key rate limit exceeded (120 requests/minute).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/events/{eventId}/reviewers":{"get":{"operationId":"listEventReviewers","tags":["Submissions"],"summary":"List an event's reviewers","description":"Returns everyone reviewing for the event, with the tracks they cover, their free-text expertise and how many reviews they hold. Use it to find the `userId` that `assignSubmissionReviewer` requires. A reviewer with status `invited` has a pending invitation and no account yet, so they cannot be assigned work. OAuth only, and requires the `admin` or `committee` role on the event — a roster names people and shows their workload.","security":[{"oauth2":["submissions:read"]}],"parameters":[{"name":"eventId","in":"path","required":true,"description":"UUID of the event. Obtain it from `GET /api/v1/events`; the event must belong to the key's organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The event's reviewers.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/ReviewerList"}}}}}},"401":{"description":"The API key is missing, unknown or revoked.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such event in the caller's organization, or no role on it.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-key rate limit exceeded (120 requests/minute).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"addEventReviewer","tags":["Submissions"],"summary":"Add a reviewer to a conference","description":"Grants the reviewer role for this event to an email address.\n\n**No email is sent.** If the address belongs to a verified account the role is granted immediately; otherwise a pending invitation is recorded and activates when that person signs up with the address. The response's `active` and `nextStep` say which happened, so a caller can tell the user whether the reviewer is live now or still needs contacting.\n\nAn address that exists but is *unverified* is deliberately NOT granted the role directly — such a row can be pre-created through guest registration, and granting it would leak peer-review data to whoever squatted the address.\n\nRequires an **OAuth access token** and **event admin**. This scope does not permit writing the content of a review.","security":[{"oauth2":["reviews:write"]}],"parameters":[{"name":"eventId","in":"path","required":true,"description":"UUID of the event. Obtain it from `GET /api/v1/events`; the event must belong to the key's organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email"],"properties":{"email":{"type":"string","format":"email"},"categoryIds":{"type":"array","items":{"type":"string"},"description":"Track/category ids to scope the reviewer to. Omit for all."}}}}}},"responses":{"201":{"description":"The reviewer was added or invited.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"type":"object","properties":{"eventId":{"type":"string","format":"uuid"},"email":{"type":"string"},"status":{"type":"string"},"active":{"type":"boolean","description":"False when only a pending invitation was recorded."},"nextStep":{"type":"string"}}}}}}}},"401":{"description":"The API key is missing, unknown or revoked.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-key rate limit exceeded (120 requests/minute).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/events/{eventId}/submissions":{"get":{"operationId":"listEventSubmissions","tags":["Submissions"],"summary":"List an event's submissions","description":"Returns the submitted (non-draft, non-withdrawn) papers/abstracts for one of the organization's events, with their review status and track. Attendee registrations are not included — use `listEventRegistrations` for those.","security":[{"apiKey":["submissions:read"]}],"parameters":[{"name":"eventId","in":"path","required":true,"description":"UUID of the event. Obtain it from `GET /api/v1/events`; the event must belong to the key's organization.","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items to return. Clamped to 100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"offset","in":"query","required":false,"description":"Number of items to skip, for paging through the collection.","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"A page of submissions.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Submission"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"401":{"description":"The API key is missing, unknown or revoked.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such event in the key's organization.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-key rate limit exceeded (120 requests/minute).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/events/{eventId}/submissions/{submissionId}":{"get":{"operationId":"getEventSubmission","tags":["Submissions"],"summary":"Read one submission and its reviews","description":"Returns a single submission in full: title, track, status, the reviews written on it with each reviewer's scores and comments, the per-criterion averages, any author rebuttal, the meta-review, and the recorded decision.\n\n**OAuth only, unlike the submission list.** The payload includes reviewer identities and the reviewers' comments written *for the organizers*. An API key resolves to an organization and holds no event role, so this authorizes as a person — specifically one with the `admin` or `committee` role on the event, the same access the dashboard's decision queue requires.","security":[{"oauth2":["submissions:read"]}],"parameters":[{"name":"eventId","in":"path","required":true,"description":"UUID of the event. Obtain it from `GET /api/v1/events`; the event must belong to the key's organization.","schema":{"type":"string","format":"uuid"}},{"name":"submissionId","in":"path","required":true,"description":"The submission's UUID, from `listEventSubmissions`.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The submission, with its reviews.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/SubmissionDetail"}}}}}},"401":{"description":"The API key is missing, unknown or revoked.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such event in the caller's organization, or no such submission in that event.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"The event has no review stage, so it has no reviews to read.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-key rate limit exceeded (120 requests/minute).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/events/{eventId}/submissions/{submissionId}/decision":{"post":{"operationId":"recordSubmissionDecision","tags":["Submissions"],"summary":"Record a decision on one submission","description":"Records an accept, reject or revise outcome on a single submission, with optional private notes and feedback for the author. Repeating the call updates the decision while it is still unsent.\n\n**This never emails anyone.** The decision is saved as a draft the author cannot see. Releasing is a separate, deliberate act: use `releaseDecisions`, which reports how many authors would be contacted and requires that number to be confirmed, or the Decisions page in the dashboard. The response always carries `emailed: false` and says how to send.","security":[{"oauth2":["decisions:write"]}],"parameters":[{"name":"eventId","in":"path","required":true,"description":"UUID of the event. Obtain it from `GET /api/v1/events`; the event must belong to the key's organization.","schema":{"type":"string","format":"uuid"}},{"name":"submissionId","in":"path","required":true,"description":"The submission's UUID, from `listEventSubmissions`.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["decision"],"properties":{"decision":{"type":"string","description":"The decision type's name as configured on this event, e.g. \"Accept\". A wrong name is answered with the valid ones in `details.availableDecisions`."},"notes":{"type":"string","description":"Private notes for the organizers. Never shown to the author."},"authorFeedback":{"type":"string","description":"Feedback the author will see — but only once decisions are released."}}}}}},"responses":{"201":{"description":"The decision was recorded, and not sent.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/RecordedDecision"}}}}}},"401":{"description":"The API key is missing, unknown or revoked.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such event in the caller's organization, or no such submission.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"No decision stage, the stage is closed, or the submission cannot carry a decision.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-key rate limit exceeded (120 requests/minute).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/events/{eventId}/tracks":{"get":{"operationId":"listEventTracks","tags":["Events"],"summary":"List an event's submission tracks","description":"Returns the tracks (categories) an event accepts submissions under, with the number of submissions in each. The `id` is what `addEventReviewer` takes when recording a reviewer's expertise, and the `name` is what `listEventSubmissions` reports per paper.","security":[{"apiKey":["submissions:read"]}],"parameters":[{"name":"eventId","in":"path","required":true,"description":"UUID of the event. Obtain it from `GET /api/v1/events`; the event must belong to the key's organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The event's tracks.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/TrackList"}}}}}},"401":{"description":"The API key is missing, unknown or revoked.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such event in the caller's organization.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-key rate limit exceeded (120 requests/minute).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/events/{eventId}/forms":{"get":{"operationId":"listEventForms","tags":["Events"],"summary":"List an event's forms","description":"Returns the event's forms — the call for papers, the registration form, any decision forms — with their question count and whether they are published. An unpublished form accepts nothing, so check `published` before concluding a conference can receive submissions.","security":[{"apiKey":["submissions:read"]}],"parameters":[{"name":"eventId","in":"path","required":true,"description":"UUID of the event. Obtain it from `GET /api/v1/events`; the event must belong to the key's organization.","schema":{"type":"string","format":"uuid"}}],"responses":{"200":{"description":"The event's forms.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/FormList"}}}}}},"401":{"description":"The API key is missing, unknown or revoked.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such event in the caller's organization.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-key rate limit exceeded (120 requests/minute).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createEventForm","tags":["Events"],"summary":"Create a call-for-papers form","description":"Creates the submission form authors fill in, from a flat list of questions. A conference with no submission form has nothing for anyone to submit to, which is what this exists to fix.\n\n**The form is created as a draft and accepts nothing until it is published** in the dashboard. The response says so, and names the remaining steps: publish it, then open the submission window with `updateEventWindows`.\n\nThis takes a question list only. Pages, sections, conditional logic, layout and ticket pricing are the form builder's job — they are decisions made by looking at a layout, and are deliberately not expressible here.","security":[{"oauth2":["events:write"]}],"parameters":[{"name":"eventId","in":"path","required":true,"description":"UUID of the event. Obtain it from `GET /api/v1/events`; the event must belong to the key's organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name","questions"],"properties":{"name":{"type":"string","description":"What the form is called in the dashboard, e.g. \"Call for Papers\"."},"questions":{"type":"array","description":"The questions, in the order authors will see them. At most 40.","items":{"type":"object","required":["label","type"],"properties":{"label":{"type":"string","description":"The question as the author reads it."},"type":{"type":"string","description":"What kind of answer it takes.","enum":["text","paragraph","rich_text","choice","multi_choice","checkbox","file","date","number","email"]},"required":{"type":"boolean","description":"Whether an author must answer. Defaults to false."},"options":{"type":"array","description":"The choices. Required for `choice` and `multi_choice`.","items":{"type":"string"}},"description":{"type":"string","description":"Help text shown under the question."}}}}}}}}},"responses":{"201":{"description":"The draft form was created.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/CreatedForm"}}}}}},"400":{"description":"A question is unlabelled, has an unknown type, or is a choice with no options. Unknown types are answered with the valid ones in `details.availableTypes`.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The API key is missing, unknown or revoked.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such event in the caller's organization.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-key rate limit exceeded (120 requests/minute).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/api/v1/events/{eventId}/registrations":{"get":{"operationId":"listEventRegistrations","tags":["Registrations"],"summary":"List an event's confirmed registrations","description":"Returns confirmed attendee registrations — name, email, ticket tier and whether the registration is paid. Use it to sync an attendee list into a CRM or to report on ticket sales. Draft (unfinished) registrations are excluded.","security":[{"apiKey":["registrations:read"]}],"parameters":[{"name":"eventId","in":"path","required":true,"description":"UUID of the event. Obtain it from `GET /api/v1/events`; the event must belong to the key's organization.","schema":{"type":"string","format":"uuid"}},{"name":"limit","in":"query","required":false,"description":"Maximum number of items to return. Clamped to 100.","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},{"name":"offset","in":"query","required":false,"description":"Number of items to skip, for paging through the collection.","schema":{"type":"integer","minimum":0,"default":0}}],"responses":{"200":{"description":"A page of registrations.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data","pagination"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Registration"}},"pagination":{"$ref":"#/components/schemas/Pagination"}}}}}},"401":{"description":"The API key is missing, unknown or revoked.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such event in the key's organization.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-key rate limit exceeded (120 requests/minute).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"post":{"operationId":"createEventRegistration","tags":["Registrations"],"summary":"Register an attendee","description":"Creates a confirmed, unpaid (comped) registration on the event's registration form and issues the attendee's QR pass — the programmatic equivalent of a walk-up registration. Use it to import attendees from another system. It does not take payment and does not create an invoice. Fires the `registration.confirmed` webhook.\n\n**Idempotent per attendee.** One confirmed registration per attendee per event, matching the website. If the email already has a non-withdrawn registration for this event, the existing one is returned with **200** and nothing is created — so retrying a timed-out request, or re-running an import, converges instead of double-booking. A `201` means a new registration was created.","security":[{"apiKey":["registrations:write"]}],"parameters":[{"name":"eventId","in":"path","required":true,"description":"UUID of the event. Obtain it from `GET /api/v1/events`; the event must belong to the key's organization.","schema":{"type":"string","format":"uuid"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/RegistrationCreate"}}}},"responses":{"200":{"description":"This attendee was already registered for this event; the existing registration is returned and nothing was created.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/CreatedRegistration"}}}}}},"201":{"description":"The registration was created.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"type":"object","required":["data"],"properties":{"data":{"$ref":"#/components/schemas/CreatedRegistration"}}}}}},"400":{"description":"The body is not valid JSON, `name`/`email` are missing or invalid, or the event has no registration form.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"The API key is missing, unknown or revoked.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"The key is valid but lacks the required scope.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"No such event in the key's organization.","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Per-key rate limit exceeded (120 requests/minute).","headers":{"RateLimit":{"$ref":"#/components/headers/RateLimit"},"RateLimit-Policy":{"$ref":"#/components/headers/RateLimitPolicy"},"RateLimit-Limit":{"$ref":"#/components/headers/RateLimitLimit"},"RateLimit-Remaining":{"$ref":"#/components/headers/RateLimitRemaining"},"RateLimit-Reset":{"$ref":"#/components/headers/RateLimitReset"},"Link":{"$ref":"#/components/headers/Link"},"Deprecation":{"$ref":"#/components/headers/Deprecation"},"Sunset":{"$ref":"#/components/headers/Sunset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}}},"components":{"headers":{"RateLimit":{"description":"Current quota state as a structured field, e.g. `\"default\";r=119;t=42` — `r` is requests remaining, `t` is seconds until the window resets. Absent when the counter is temporarily unavailable.","schema":{"type":"string"}},"RateLimitPolicy":{"description":"The quota being applied, e.g. `\"default\";q=120;w=60` — `q` requests per `w` seconds. Always present.","schema":{"type":"string"}},"RateLimitLimit":{"description":"Requests permitted per window. The widely-deployed spelling of the same ceiling as `RateLimit-Policy`.","schema":{"type":"integer"}},"RateLimitRemaining":{"description":"Requests left in the current window. Absent when the counter is temporarily unavailable — treat absence as unknown, not as zero.","schema":{"type":"integer"}},"RateLimitReset":{"description":"Seconds until the current window resets. A delta, not a timestamp.","schema":{"type":"integer"}},"RetryAfter":{"description":"Seconds to wait before retrying. Present on 429 responses (RFC 9110).","schema":{"type":"integer"}},"Link":{"description":"Typed links for this API: `rel=\"service-desc\"` points at this document, `rel=\"service-doc\"` at the human documentation, and `rel=\"deprecation\"` at the deprecation policy once an operation is deprecated (RFC 8631, RFC 9745).","schema":{"type":"string"}},"Deprecation":{"description":"Present ONLY on a deprecated operation: the date the deprecation was announced, as a structured-field Date (`@<unix-seconds>`, RFC 9745).","schema":{"type":"string"},"required":false},"Sunset":{"description":"Present ONLY on a deprecated operation: the HTTP-date after which it stops responding (RFC 8594). Never sooner than the published notice period.","schema":{"type":"string"},"required":false}},"securitySchemes":{"apiKey":{"type":"http","scheme":"bearer","bearerFormat":"cong_live_<secret>","description":"An organization API key, sent as `Authorization: Bearer cong_live_…`.\n\nCreate one in *Organization settings → API*. The secret is shown once and stored only as a hash, so it cannot be recovered — rotate by creating a new key and revoking the old one. Keys carry scopes; an operation refuses with 403 if its scope is missing. Rate limit: 120 requests/minute per key.\n\nAvailable scopes: `events:read`, `submissions:read`, `registrations:read`, `registrations:write`."},"oauth2":{"type":"oauth2","description":"An OAuth 2.1 access token obtained on a user's behalf, sent as `Authorization: Bearer cong_at_…`.\n\nDiscovery starts at `/.well-known/oauth-protected-resource`; an unauthenticated request to this API also returns a `WWW-Authenticate` header pointing there. PKCE (S256) is required of every client, including confidential ones.\n\nA grant is scoped to **one organization**, chosen by the user on the consent screen, and is bounded by that user's role in it — scopes are re-checked against the current role on every request, so a demotion takes effect immediately.","flows":{"authorizationCode":{"authorizationUrl":"https://www.congressio.net/oauth/authorize","tokenUrl":"https://www.congressio.net/oauth/token","refreshUrl":"https://www.congressio.net/oauth/token","scopes":{"events:read":"Read the organization's events, including drafts.","submissions:read":"Read submitted papers and abstracts, with their review status and track.","registrations:read":"Read the attendee list, including names, email addresses and ticket tiers.","registrations:write":"Register attendees and issue their passes.","events:write":"Create and modify events. OAuth only — never granted to an API key.","decisions:write":"Release acceptance decisions, which emails every author. OAuth only, and the only scope whose use contacts people outside the organization.","reviews:write":"Manage the review process: add reviewers and assign them to submissions. Does not allow writing the content of a review. OAuth only."}}}}},"schemas":{"Error":{"type":"object","title":"Error","description":"Every non-2xx response has this shape. Branch on `code`, show `message`, act on `hint`.","required":["error","code","message","hint","docs"],"properties":{"error":{"type":"string","description":"Human-readable summary (same text as `message`)."},"code":{"type":"string","description":"Stable machine-readable error code.","enum":["bad_request","unauthorized","forbidden","not_found","method_not_allowed","rate_limited","internal_error"]},"message":{"type":"string","description":"Human-readable summary."},"hint":{"type":"string","description":"What the caller should do to resolve the error."},"docs":{"type":"string","format":"uri","description":"Documentation for this API."},"details":{"type":"object","additionalProperties":true,"description":"Machine-readable specifics, present only when resolving the error needs data rather than prose. `publishEvent`'s 409 carries `{ missing: [...] }` — the setup items to show the user and echo back."}},"examples":[{"error":"Missing required scope: registrations:write","code":"forbidden","message":"Missing required scope: registrations:write","hint":"The key is valid but lacks the scope this operation needs. Re-create the key with the required scope.","docs":"https://www.congressio.net/developers"}]},"Pagination":{"type":"object","title":"Pagination","description":"Echoes the applied window plus the number of items in this page. There is no total count; a page shorter than `limit` is the last page.","required":["limit","offset","count"],"properties":{"limit":{"type":"integer","description":"Applied page size."},"offset":{"type":"integer","description":"Applied offset."},"count":{"type":"integer","description":"Items returned in this page."}}},"Venue":{"type":"object","title":"Venue","description":"Where the conference takes place. Every field is null for a fully online conference.","required":["name","address","city","postalCode","country"],"properties":{"name":{"type":["string","null"],"description":"Venue name."},"address":{"type":["string","null"],"description":"Free-text postal address."},"city":{"type":["string","null"],"description":"City."},"postalCode":{"type":["string","null"],"description":"Postal code."},"country":{"type":["string","null"],"description":"ISO 3166-1 alpha-2 country code."}}},"PublicEvent":{"type":"object","title":"PublicEvent","description":"A publicly visible conference — the same information the public event page shows.","required":["slug","name","description","startDate","endDate","timezone","venue","organization","programPublished","url","updatedAt"],"properties":{"slug":{"type":"string","description":"URL slug; use it with `getPublicEvent`."},"name":{"type":"string","description":"Conference name."},"description":{"type":["string","null"],"description":"Organizer's description. May contain HTML."},"startDate":{"type":["string","null"],"format":"date-time","description":"First day, ISO 8601."},"endDate":{"type":["string","null"],"format":"date-time","description":"Last day, ISO 8601."},"timezone":{"type":"string","description":"IANA timezone the schedule is expressed in."},"venue":{"$ref":"#/components/schemas/Venue"},"organization":{"type":"object","description":"The organization hosting the conference.","required":["name"],"properties":{"name":{"type":["string","null"],"description":"Organization name."}}},"programPublished":{"type":"boolean","description":"Whether the session schedule is public. When false, the program page is organizer-only."},"url":{"type":"string","format":"uri","description":"Absolute URL of the public event page."},"updatedAt":{"type":["string","null"],"format":"date-time","description":"Last modification, ISO 8601."}}},"Event":{"type":"object","title":"Event","description":"An event owned by the key's organization, at any status (draft, active, archived).","required":["id","slug","name","description","status","startDate","endDate","timezone","registrationCapacity","createdAt"],"properties":{"id":{"type":"string","format":"uuid","description":"Event UUID — the `eventId` path parameter."},"slug":{"type":"string","description":"URL slug."},"name":{"type":"string","description":"Event name."},"description":{"type":["string","null"],"description":"Description. May contain HTML."},"status":{"type":"string","description":"Lifecycle status.","enum":["draft","active","archived"]},"startDate":{"type":["string","null"],"format":"date-time","description":"First day, ISO 8601."},"endDate":{"type":["string","null"],"format":"date-time","description":"Last day, ISO 8601."},"timezone":{"type":"string","description":"IANA timezone."},"registrationCapacity":{"type":["integer","null"],"description":"Maximum confirmed registrations; null means unlimited."},"createdAt":{"type":["string","null"],"format":"date-time","description":"When the event was created, ISO 8601."}}},"SubmissionDetail":{"type":"object","title":"SubmissionDetail","description":"One submission with its reviews. Confidential to the event's committee: it names reviewers and includes the comments they wrote for the organizers rather than for the author.","required":["id","title","status","reviews"],"properties":{"id":{"type":"string","format":"uuid","description":"Submission UUID."},"eventId":{"type":"string","format":"uuid","description":"The event this submission belongs to."},"title":{"type":"string","description":"Display title, resolved from the submission form's title field."},"status":{"type":"string","description":"Review status, e.g. `submitted`, `under_review`, `decided`."},"track":{"type":"string","nullable":true,"description":"Category name(s), joined when a submission has several."},"round":{"type":"integer","description":"The review round these reviews belong to. Multi-round events reuse the stage system, and this is the current (highest) round."},"reviewCount":{"type":"integer","description":"How many reviews exist for this round."},"averageScore":{"type":"number","nullable":true,"description":"Mean overall score across this round's reviews; null when none are scored."},"maxScore":{"type":"number","description":"Top of the scale `averageScore` and each review's `overallScore` are on."},"recommendedDecision":{"type":"string","nullable":true,"description":"What the configured score thresholds suggest. Advisory only — no decision is recorded from it."},"reviews":{"type":"array","description":"The reviews written in this round, newest first.","items":{"type":"object","properties":{"reviewer":{"type":"string","nullable":true,"description":"The reviewer's name. Confidential to the committee."},"overallScore":{"type":"number","nullable":true,"description":"This reviewer's overall score, on the `maxScore` scale."},"criteria":{"type":"array","description":"Per-criterion scores from this reviewer.","items":{"type":"object","properties":{"label":{"type":"string","description":"The criterion's label on the review form."},"value":{"type":"number","description":"The score given for that criterion."}}}},"commentsForAuthor":{"type":"string","nullable":true,"description":"Feedback intended for the author, released with the decision."},"commentsForOrganizers":{"type":"string","nullable":true,"description":"Written for the organizers, NOT for the author. Never relay this to an author."},"attachmentCount":{"type":"integer","description":"How many files the reviewer attached. The files themselves are not returned here."}}}},"criterionAverages":{"type":"array","description":"Mean score per criterion across all of this round's reviews.","items":{"type":"object","properties":{"label":{"type":"string","description":"The criterion's label."},"average":{"type":"number","description":"Mean score for that criterion."}}}},"metaReview":{"type":"object","nullable":true,"description":"The aggregate meta-review for this round, if one has been written."},"rebuttal":{"type":"object","nullable":true,"description":"The authors' response to the reviews, if the event allows rebuttals and one was submitted."},"decision":{"type":"object","nullable":true,"description":"The recorded decision, if any. `isFinal` false means it has not been released to the author."}}},"RecordedDecision":{"type":"object","title":"RecordedDecision","description":"A decision saved against a submission. Always unsent — see `emailed`.","required":["id","decision","emailed"],"properties":{"id":{"type":"string","format":"uuid","description":"The decision record's UUID."},"eventId":{"type":"string","format":"uuid","description":"The event the submission belongs to."},"submissionId":{"type":"string","format":"uuid","description":"The submission the decision is about."},"decision":{"type":"string","description":"The decision type that was recorded."},"emailed":{"type":"boolean","description":"Always false from this endpoint. The author has not been contacted and cannot see the decision."},"status":{"type":"string","description":"Human-readable restatement of `emailed`, for a caller that relays prose to a user."},"nextStep":{"type":"string","description":"How a human actually sends decisions: the dashboard's Decisions page, or `releaseDecisions`."}}},"TrackList":{"type":"object","title":"TrackList","description":"An event's submission tracks.","required":["eventId","tracks"],"properties":{"eventId":{"type":"string","format":"uuid","description":"The event the tracks belong to."},"tracks":{"type":"array","description":"Tracks in display order.","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Track UUID — what `addEventReviewer` takes as expertise."},"name":{"type":"string","description":"Track name, as reported per submission by `listEventSubmissions`."},"color":{"type":"string","nullable":true,"description":"Display colour used in the dashboard."},"submissionCount":{"type":"integer","description":"How many submissions are filed under it."}}}}}},"ReviewerList":{"type":"object","title":"ReviewerList","description":"An event's reviewers, including pending invitations. Names people and their workload.","required":["eventId","reviewers"],"properties":{"eventId":{"type":"string","format":"uuid","description":"The event the reviewers serve."},"reviewers":{"type":"array","description":"Active reviewers and pending invitations.","items":{"type":"object","properties":{"userId":{"type":"string","format":"uuid","nullable":true,"description":"The id `assignSubmissionReviewer` takes. Null for a pending invitation, which cannot yet be assigned work."},"name":{"type":"string","nullable":true,"description":"Display name, null until they sign up."},"email":{"type":"string","description":"The address the reviewer role is held against."},"status":{"type":"string","description":"`active` once they hold the role; `invited` while an invitation is pending; `declined` if refused.","enum":["active","invited","declined"]},"tracks":{"type":"array","description":"Names of the tracks this reviewer covers.","items":{"type":"string"}},"expertise":{"type":"string","description":"Free-text keywords recorded for this reviewer."},"assignedCount":{"type":"integer","description":"Reviews currently assigned to them."},"completedCount":{"type":"integer","description":"How many of those they have finished."}}}}}},"FormList":{"type":"object","title":"FormList","description":"The forms attached to an event.","required":["eventId","forms"],"properties":{"eventId":{"type":"string","format":"uuid","description":"The event the forms belong to."},"forms":{"type":"array","description":"Every form on the event, published or not.","items":{"type":"object","properties":{"id":{"type":"string","format":"uuid","description":"Form UUID."},"name":{"type":"string","description":"The form's name in the dashboard."},"type":{"type":"string","description":"`submission` for a call for papers, `registration` for attendees, `decision` for the decision record."},"published":{"type":"boolean","description":"False means the form accepts nothing, whatever the submission window says."},"fieldCount":{"type":"integer","description":"How many questions it asks."}}}}}},"CreatedForm":{"type":"object","title":"CreatedForm","description":"A newly created submission form. Always a draft.","required":["id","published"],"properties":{"id":{"type":"string","format":"uuid","nullable":true,"description":"The new form's UUID."},"eventId":{"type":"string","format":"uuid","description":"The event it belongs to."},"name":{"type":"string","description":"The form's name."},"type":{"type":"string","description":"Always `submission` from this endpoint."},"questionCount":{"type":"integer","description":"How many questions were created."},"published":{"type":"boolean","description":"Always false. The form accepts nothing until a human publishes it."},"nextStep":{"type":"string","description":"What remains to be done: review and publish the form, then open the submission window."}}},"Submission":{"type":"object","title":"Submission","description":"A paper, abstract or talk submitted to an event.","required":["id","title","status","track"],"properties":{"id":{"type":"string","format":"uuid","description":"Submission UUID."},"title":{"type":"string","description":"Display title, resolved from the submission form's title field."},"status":{"type":"string","description":"Review status. `draft` and `withdrawn` submissions are never listed.","enum":["submitted","under_review","accepted","rejected","revision_requested"]},"track":{"type":["string","null"],"description":"Track/category name(s), joined with `; ` when a submission is in several."}}},"Registration":{"type":"object","title":"Registration","description":"A confirmed attendee registration.","required":["id","name","email","status","tier","paid","submittedAt"],"properties":{"id":{"type":"string","format":"uuid","description":"Registration UUID."},"name":{"type":["string","null"],"description":"Attendee name."},"email":{"type":["string","null"],"format":"email","description":"Attendee email, taken from the registration form or the account."},"status":{"type":"string","description":"Always `submitted` — only confirmed registrations are listed."},"tier":{"type":["string","null"],"description":"Ticket tier chosen on the registration form."},"paid":{"type":"boolean","description":"True when a payment for this registration is settled."},"submittedAt":{"type":["string","null"],"format":"date-time","description":"When the registration was confirmed, ISO 8601."}}},"RegistrationCreate":{"type":"object","title":"RegistrationCreate","description":"Body of `createEventRegistration`.","required":["name","email"],"additionalProperties":false,"properties":{"name":{"type":"string","minLength":1,"description":"Attendee's full name, as it should appear on the badge."},"email":{"type":"string","format":"email","description":"Attendee's email. An existing account with this address is reused; otherwise a passwordless account is created."},"tier":{"type":"string","description":"Ticket tier — the value or label of an option on the event's registration form. Omit to register without a tier."}}},"CreatedRegistration":{"type":"object","title":"CreatedRegistration","description":"The registration created by `createEventRegistration`.","required":["id","registrationNumber","name","email","tier","status","paid","passSerial","passToken"],"properties":{"id":{"type":"string","format":"uuid","description":"Registration UUID."},"registrationNumber":{"type":["integer","null"],"description":"Per-event sequence number shown to the organizer."},"name":{"type":"string","description":"Attendee name, as submitted."},"email":{"type":"string","format":"email","description":"Attendee email, normalized to lower case."},"tier":{"type":["string","null"],"description":"Ticket tier recorded on the registration."},"status":{"type":"string","description":"`submitted` for a newly created registration. When an existing one is returned (200) this is its current status, which is never `draft` or `withdrawn`."},"paid":{"type":"boolean","description":"Always false — API-created registrations are comped."},"passSerial":{"type":["string","null"],"description":"Serial of the issued QR pass."},"passToken":{"type":["string","null"],"description":"Signed token encoding the pass; scanned at check-in. Treat as a credential."}}}}}}