{"openapi":"3.1.0","info":{"title":"Rollcall API","version":"1.0.0","summary":"Create and publish events, import passes, and read check-in history.","description":"Create, update and publish events, read event details, import organizer-verified guests as passes, and poll check-in history.\n\n## Guest RSVP and organizer imports\n\nGuests RSVP on the Rollcall event page at the event's `url`. No guest RSVPs over the API. An organizer can use a write-scoped key to import guests it has already verified on its own site. The organizer vouches for identity, age and waiver acceptance. Door staff still check ID. Importing a pass does not check anyone in.\n\n## Authentication\n\nSend `Authorization: Bearer rc_live_<32 letters and numbers>`. Owners and admins make keys under Team & settings, Organization, API. Copy a new key when it is shown. An organization can have 10 active keys.\n\nKeys default to read-only. Existing keys without scopes remain read-only. Enable Can create events to grant `events:write` for event creation, updates and publishing. Enable Can create passes to grant `passes:write` for pass import and cancellation. A write without its required scope returns `403 FORBIDDEN`. Every valid key can read its organization's events, imported passes and check-in history. Unknown, revoked or suspended-organization keys return `401`.\n\n## Rate limits\n\nReads allow 60 requests a minute per key, with a burst of 120. Writes have a separate budget: 600 requests a minute, with a burst of 1,200. A batch import spends one write request. JSON bodies are limited to 64 KB by the public proxy. A `429` response includes `Retry-After` in seconds. Keyless traffic and failed authentication also have address budgets. Successful reads are cacheable for 15 seconds. Writes return Cache-Control: no-store.\n\n## Event writes\n\nUse `POST /events` with a required organization-unique `externalId` to create a draft, optionally with `publish: true` to publish in the same transaction. Repeating the external ID returns the existing event with `created: false` and changes nothing. Use a published slug or `ext:{externalId}` to PATCH or publish; any key can GET an external reference, including a draft in its own organization. Drafts have null slug and URL and never appear in the list.\n\nDates are ISO strings with an offset; timezone is an IANA name. Descriptions use the app's markdown normalization. Each location part is optional; null clears it. Null capacity removes the cap. Access is link or passcode; a passcode is required when first enabling passcode access and is never returned. Unknown fields return INVALID with field. PATCH retains the app's scheduling and guest change notices for time/place changes. Publishing twice is a 200 no-op; editing or publishing a cancelled event returns 409 CONFLICT. No event-count limit is enforced at creation.\n\nThe cover, palette, questions, waiver, plus-ones, invite-only access, cancelling and deleting stay in the organizer app. Cancelling notifies guests.\n\n## Polling check-ins\n\nEntries appear about 10 seconds after recording, after a settle window lets mutations commit. Poll every 30-60 seconds with the returned `nextCursor`. Deduplicate on entry `id`. Save the cursor even when the page is empty or short. Unapplied door presentations are omitted. The feed includes undo rows. The `at` field is the original scan time, even for an offline scan synced later. Webhooks are not available.\n\n## Key storage\n\nKeep write keys on your server, never in browser code. Read keys can expose guest contact details through the feed; keep them private too. CORS allows any origin (`Access-Control-Allow-Origin: *`).\n\n## Terms and reference\n\nUse of the API is covered by the [Rollcall Terms of Service](https://letsrollcall.com/terms). This specification is served at [/api/v1/openapi.json](https://letsrollcall.com/api/v1/openapi.json). A plain-text summary is at [/llms.txt](https://letsrollcall.com/llms.txt)."},"servers":[{"url":"https://letsrollcall.com/api/v1","description":"Production"}],"tags":[{"name":"Events","description":"Create, update, publish and read your organization's events."},{"name":"Passes","description":"Organizer-imported passes."},{"name":"Check-ins","description":"Settled check-in history."},{"name":"Meta","description":"The API's own description."}],"security":[{"bearerKey":[]}],"paths":{"/events/{slug}/passes":{"post":{"tags":["Passes"],"operationId":"importPasses","summary":"Import guests as passes","description":"Requires passes:write. Import 1 to 100 guests already verified by the organizer. No guest RSVPs over the API. The organizer vouches for identity, age and waiver; door staff still check ID. Each guest is processed independently. A bad guest does not fail the batch. externalId is unique per event: importing it again returns the current pass with created: false and changes nothing. A full event returns a per-guest CAPACITY error. A waiver event without waiverAccepted returns status waiver, a code and an empty qrValue, with no going-count bump. Accepted waivers record the organizer's version and acceptance time. Import never checks anyone in. The event must be published and belong to your organization. JSON bodies are limited to 64 KB by the public proxy.","x-rate-limit":{"requests":600,"per":"minute","burst":1200},"parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportPassesRequest"},"example":{"guests":[{"externalId":"guest_1","name":"Alex Guest","phone":"+17025550111","ageVerified":"attested","waiverAccepted":{"version":"waiver-v1","at":"2026-10-08T17:42:10.512Z"}}]}}}},"responses":{"200":{"description":"One result per guest, in request order.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportPassesResponse"}}}},"400":{"description":"Malformed request body, cursor or limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"INVALID","message":"Invalid cursor or limit."}}}}},"401":{"description":"The key is missing, malformed, unknown or revoked, or its organization is suspended.","headers":{"WWW-Authenticate":{"description":"Always `Bearer`.","schema":{"type":"string","examples":["Bearer"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"UNAUTHORIZED","message":"That API key is not valid."}}}}},"403":{"description":"This key lacks passes:write scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"FORBIDDEN","message":"This key needs passes:write scope."}}}}},"404":{"description":"The event is unpublished, cancelled, unknown or outside your organization, or the pass does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"NOT_FOUND","message":"No such event."}}}}},"413":{"description":"The JSON body exceeds 64 KB at the public proxy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"INVALID","message":"Body exceeds 64 KB."}}}}},"429":{"description":"Too many requests. Wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds to wait before the next request.","required":true,"schema":{"type":"integer","minimum":1,"examples":[12]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests. Slow down."}}}}}}}},"/events/{slug}/passes/{externalId}":{"get":{"tags":["Passes"],"operationId":"getImportedPass","summary":"Get an imported pass","description":"Any valid organization key can re-fetch an imported pass. Returns its current status and QR value, with created: false. The event must be published and belong to your organization.","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"externalId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"}}],"x-rate-limit":{"requests":60,"per":"minute","burst":120},"responses":{"200":{"description":"The imported pass.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportedPassResponse"}}}},"401":{"description":"The key is missing, malformed, unknown or revoked, or its organization is suspended.","headers":{"WWW-Authenticate":{"description":"Always `Bearer`.","schema":{"type":"string","examples":["Bearer"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"UNAUTHORIZED","message":"That API key is not valid."}}}}},"404":{"description":"The event is unpublished, cancelled, unknown or outside your organization, or the pass does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"NOT_FOUND","message":"No such event."}}}}},"429":{"description":"Too many requests. Wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds to wait before the next request.","required":true,"schema":{"type":"integer","minimum":1,"examples":[12]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests. Slow down."}}}}}}},"delete":{"tags":["Passes"],"operationId":"cancelImportedPass","summary":"Cancel an imported pass","description":"Requires passes:write. Cancels the pass and removes its going count if counted. Returns status cancelled and an empty qrValue. Repeating cancellation is a 200 no-op. A guest currently inside is cancelled too; check-in history is retained. The event must be published and belong to your organization.","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"externalId","in":"path","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"}}],"x-rate-limit":{"requests":600,"per":"minute","burst":1200},"responses":{"200":{"description":"The cancelled pass.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ImportedPassResponse"}}}},"401":{"description":"The key is missing, malformed, unknown or revoked, or its organization is suspended.","headers":{"WWW-Authenticate":{"description":"Always `Bearer`.","schema":{"type":"string","examples":["Bearer"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"UNAUTHORIZED","message":"That API key is not valid."}}}}},"403":{"description":"This key lacks passes:write scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"FORBIDDEN","message":"This key needs passes:write scope."}}}}},"404":{"description":"The event is unpublished, cancelled, unknown or outside your organization, or the pass does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"NOT_FOUND","message":"No such event."}}}}},"413":{"description":"The request body exceeds 64 KB at the public proxy.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"INVALID","message":"Body exceeds 64 KB."}}}}},"429":{"description":"Too many requests. Wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds to wait before the next request.","required":true,"schema":{"type":"integer","minimum":1,"examples":[12]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests. Slow down."}}}}}}}},"/events/{slug}/checkins":{"get":{"tags":["Check-ins"],"operationId":"listCheckins","summary":"Poll check-in history","description":"Any valid organization key can poll this feed. Entries appear about 10 seconds after they are recorded, after a settle window lets mutations commit. Poll every 30-60 seconds with the returned nextCursor and deduplicate on entry id. The feed includes arrivals, departures, undo rows and walkup creation. Unapplied door presentations are omitted. Rows are ordered by creation time, then entry ID. at is the original scan time, not sync time. Omit cursor to start at the beginning. Always save nextCursor, even on an empty or short page: it also advances past omitted unapplied rows. The event must be published and belong to your organization. No webhooks are sent.","parameters":[{"name":"slug","in":"path","required":true,"schema":{"type":"string"}},{"name":"cursor","in":"query","schema":{"type":"string"},"description":"The opaque nextCursor from the previous page."},{"name":"limit","in":"query","schema":{"type":"integer","minimum":1,"maximum":500,"default":200}}],"x-rate-limit":{"requests":60,"per":"minute","burst":120},"responses":{"200":{"description":"Settled applied entries and the next polling cursor.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CheckinsResponse"}}}},"400":{"description":"Malformed request body, cursor or limit.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"INVALID","message":"Invalid cursor or limit."}}}}},"401":{"description":"The key is missing, malformed, unknown or revoked, or its organization is suspended.","headers":{"WWW-Authenticate":{"description":"Always `Bearer`.","schema":{"type":"string","examples":["Bearer"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"UNAUTHORIZED","message":"That API key is not valid."}}}}},"404":{"description":"The event is unpublished, cancelled, unknown or outside your organization, or the pass does not exist.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"NOT_FOUND","message":"No such event."}}}}},"429":{"description":"Too many requests. Wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds to wait before the next request.","required":true,"schema":{"type":"integer","minimum":1,"examples":[12]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests. Slow down."}}}}}}}},"/":{"get":{"tags":["Meta"],"operationId":"getApiIndex","summary":"API index","description":"A self-describing pointer to this specification and the docs. No key needed.","security":[],"responses":{"200":{"description":"The API's name, version, and where its description lives.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ApiIndex"},"example":{"name":"Rollcall API","version":"1.0.0","openapi":"https://letsrollcall.com/api/v1/openapi.json","docs":"https://letsrollcall.com/developers"}}}},"429":{"description":"Too many requests. Wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds to wait before the next request.","required":true,"schema":{"type":"integer","minimum":1,"examples":[12]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests. Slow down."}}}}}}}},"/events":{"post":{"tags":["Events"],"operationId":"createEvent","summary":"Create an event","description":"Requires events:write. Creates a draft with an organization-unique externalId. Reusing it returns the existing event with created: false and changes nothing. Set publish: true to create and publish atomically. The key's creator is recorded as the event creator; createdVia and createdByApiKeyId record API attribution.","x-required-scope":"events:write","x-rate-limit":{"requests":600,"per":"minute","burst":1200},"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventCreateRequest"}}}},"responses":{"200":{"description":"The event. Draft slug and URL are null; created is included only on create.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventWriteResponse"}}},"headers":{"Cache-Control":{"schema":{"type":"string","const":"no-store"}}}},"400":{"description":"Invalid event fields, including unknown fields. Validation errors identify the JSON field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"INVALID","message":"timezone is not a recognized time zone","field":"timezone"}}}}},"401":{"description":"The key is missing, malformed, unknown or revoked, or its organization is suspended.","headers":{"WWW-Authenticate":{"description":"Always `Bearer`.","schema":{"type":"string","examples":["Bearer"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"UNAUTHORIZED","message":"That API key is not valid."}}}}},"403":{"description":"Missing events:write scope, or the organization was suspended before the write committed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"FORBIDDEN","message":"This key needs events:write scope."}}}}},"404":{"description":"No event in your organization matches this reference.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"NOT_FOUND","message":"No such event."}}}}},"409":{"description":"A cancelled event cannot be updated or published, or a shared event invariant conflicts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"CONFLICT","message":"A cancelled event cannot be updated or published."}}}}},"413":{"description":"The public proxy limits bodies to 64 KB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"INVALID","message":"Body exceeds 64 KB."}}}}},"429":{"description":"Too many requests. Wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds to wait before the next request.","required":true,"schema":{"type":"integer","minimum":1,"examples":[12]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests. Slow down."}}}}}}},"get":{"tags":["Events"],"operationId":"listEvents","summary":"List events","description":"Your published and cancelled events, soonest first, leaving out anything that ended more than 24 hours ago. Drafts are never included. At most 100 events.","x-rate-limit":{"requests":60,"per":"minute","burst":120},"responses":{"200":{"description":"The events, soonest first.","headers":{"Cache-Control":{"description":"Cacheable for 15 seconds.","schema":{"type":"string","examples":["private, max-age=15"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventListResponse"},"example":{"events":[{"slug":"rooftop-night-k3m9x2q7ab","title":"Rooftop Night","status":"published","startsAt":"2026-11-14T21:00:00-08:00","endsAt":"2026-11-15T01:00:00-08:00","timezone":"America/Los_Angeles","venue":{"name":"The Rooftop","address":"123 Main St","city":"Las Vegas"},"coverImageUrl":"https://happy-animal-123.convex.cloud/api/storage/6b0c1b6e-0000-4000-8000-000000000000","access":"link","ageGate":"scanOptional","waiver":true,"capacity":120,"counts":{"going":84,"reserved":6,"waitlist":0,"spotsLeft":30},"rsvpOpen":true,"url":"https://letsrollcall.com/event/rooftop-night-k3m9x2q7ab"}],"asOf":"2026-10-08T17:42:10.512Z"}}}},"401":{"description":"The key is missing, malformed, unknown or revoked, or its organization is suspended.","headers":{"WWW-Authenticate":{"description":"Always `Bearer`.","schema":{"type":"string","examples":["Bearer"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"UNAUTHORIZED","message":"That API key is not valid."}}}}},"429":{"description":"Too many requests. Wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds to wait before the next request.","required":true,"schema":{"type":"integer","minimum":1,"examples":[12]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests. Slow down."}}}}}}}},"/events/{ref}/publish":{"post":{"tags":["Events"],"operationId":"publishEvent","summary":"Publish an event","description":"Requires events:write. Accepts a published slug or ext:{externalId}. Mints a slug for a draft and runs the app's publish side effects. Repeating it on a published event returns it unchanged. Cancelled events return 409. No body is needed; an optional JSON body must be empty.","x-required-scope":"events:write","x-rate-limit":{"requests":600,"per":"minute","burst":1200},"parameters":[{"name":"ref","in":"path","required":true,"description":"A published event slug, or ext:{externalId} for any of your organization's events, including drafts.","schema":{"type":"string","examples":["rooftop-night-k3m9x2q7ab","ext:opening_night"]}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","required":[],"properties":{},"additionalProperties":false}}}},"responses":{"200":{"description":"The event. Draft slug and URL are null; created is included only on create.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventWriteResponse"}}},"headers":{"Cache-Control":{"schema":{"type":"string","const":"no-store"}}}},"400":{"description":"Invalid event fields, including unknown fields. Validation errors identify the JSON field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"INVALID","message":"timezone is not a recognized time zone","field":"timezone"}}}}},"401":{"description":"The key is missing, malformed, unknown or revoked, or its organization is suspended.","headers":{"WWW-Authenticate":{"description":"Always `Bearer`.","schema":{"type":"string","examples":["Bearer"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"UNAUTHORIZED","message":"That API key is not valid."}}}}},"403":{"description":"Missing events:write scope, or the organization was suspended before the write committed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"FORBIDDEN","message":"This key needs events:write scope."}}}}},"404":{"description":"No event in your organization matches this reference.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"NOT_FOUND","message":"No such event."}}}}},"409":{"description":"A cancelled event cannot be updated or published, or a shared event invariant conflicts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"CONFLICT","message":"A cancelled event cannot be updated or published."}}}}},"413":{"description":"The public proxy limits bodies to 64 KB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"INVALID","message":"Body exceeds 64 KB."}}}}},"429":{"description":"Too many requests. Wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds to wait before the next request.","required":true,"schema":{"type":"integer","minimum":1,"examples":[12]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests. Slow down."}}}}}}}},"/events/{ref}":{"patch":{"tags":["Events"],"operationId":"updateEvent","summary":"Update an event","description":"Requires events:write. Applies a partial update to a draft or published event through the same validation and side effects as the app, including rescheduling close-out, spot release, reminders and existing guest notices for time/place changes. Omit a field to leave it unchanged; null clears capacity or a location part. Cancelled events return 409. The externalId is immutable.","x-required-scope":"events:write","x-rate-limit":{"requests":600,"per":"minute","burst":1200},"parameters":[{"name":"ref","in":"path","required":true,"description":"A published event slug, or ext:{externalId} for any of your organization's events, including drafts.","schema":{"type":"string","examples":["rooftop-night-k3m9x2q7ab","ext:opening_night"]}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventPatchRequest"}}}},"responses":{"200":{"description":"The event. Draft slug and URL are null; created is included only on create.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventWriteResponse"}}},"headers":{"Cache-Control":{"schema":{"type":"string","const":"no-store"}}}},"400":{"description":"Invalid event fields, including unknown fields. Validation errors identify the JSON field.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"INVALID","message":"timezone is not a recognized time zone","field":"timezone"}}}}},"401":{"description":"The key is missing, malformed, unknown or revoked, or its organization is suspended.","headers":{"WWW-Authenticate":{"description":"Always `Bearer`.","schema":{"type":"string","examples":["Bearer"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"UNAUTHORIZED","message":"That API key is not valid."}}}}},"403":{"description":"Missing events:write scope, or the organization was suspended before the write committed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"FORBIDDEN","message":"This key needs events:write scope."}}}}},"404":{"description":"No event in your organization matches this reference.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"NOT_FOUND","message":"No such event."}}}}},"409":{"description":"A cancelled event cannot be updated or published, or a shared event invariant conflicts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"CONFLICT","message":"A cancelled event cannot be updated or published."}}}}},"413":{"description":"The public proxy limits bodies to 64 KB.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"INVALID","message":"Body exceeds 64 KB."}}}}},"429":{"description":"Too many requests. Wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds to wait before the next request.","required":true,"schema":{"type":"integer","minimum":1,"examples":[12]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests. Slow down."}}}}}}},"get":{"tags":["Events"],"operationId":"getEvent","summary":"Get one event","description":"One event by a published slug or ext:{externalId}. External references return EventWrite, including drafts, for any valid key in the same organization. Slug reads retain EventDetail. Both include everything in the list entry plus the description, the organizer, the host updates and the event's colors: enough to build a landing page for the event on your own site. A slug that does not exist, belongs to a draft, or belongs to another organization all get the same `404`. For a password-protected or invite-only event the description and updates are empty and the venue name and address are `null`, because its public page shows only a teaser until a guest gets in.","x-rate-limit":{"requests":60,"per":"minute","burst":120},"parameters":[{"name":"ref","in":"path","required":true,"description":"A published event slug, or ext:{externalId} for any of your organization's events, including drafts.","schema":{"type":"string","examples":["rooftop-night-k3m9x2q7ab","ext:opening_night"]}}],"responses":{"200":{"description":"The event, in full.","headers":{"Cache-Control":{"description":"Cacheable for 15 seconds.","schema":{"type":"string","examples":["private, max-age=15"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/EventByRefResponse"},"example":{"event":{"slug":"rooftop-night-k3m9x2q7ab","title":"Rooftop Night","status":"published","startsAt":"2026-11-14T21:00:00-08:00","endsAt":"2026-11-15T01:00:00-08:00","timezone":"America/Los_Angeles","venue":{"name":"The Rooftop","address":"123 Main St","city":"Las Vegas"},"coverImageUrl":"https://happy-animal-123.convex.cloud/api/storage/6b0c1b6e-0000-4000-8000-000000000000","access":"link","ageGate":"scanOptional","waiver":true,"capacity":120,"counts":{"going":84,"reserved":6,"waitlist":0,"spotsLeft":30},"rsvpOpen":true,"url":"https://letsrollcall.com/event/rooftop-night-k3m9x2q7ab","description":{"html":"<p>Three floors, one rooftop. <strong>Dress to be seen.</strong></p><ul><li><p>Doors at 9</p></li><li><p>Last call at 12:45</p></li></ul>","text":"Three floors, one rooftop. Dress to be seen.\n\n- Doors at 9\n- Last call at 12:45"},"organization":{"name":"Velvet Room","handle":"velvet-room","url":"https://letsrollcall.com/velvet-room","avatarUrl":"https://happy-animal-123.convex.cloud/api/storage/0a1b2c3d-0000-4000-8000-000000000000"},"updates":[{"postedAt":"2026-11-12T19:30:00.000Z","subject":"Doors move to 9:30","html":"<p>Doors now open at 9:30 PM.</p>","text":"Doors now open at 9:30 PM."}],"theme":{"style":"color","colors":{"bg":"#0C0614","text":"#F7ECFF","muted":"#D6C6EC","accent":"#FF4E9C","accentText":"#22000C","g1":"#E0176F","g2":"#2A48FF","g3":"#FF5A1F","g4":"#7B1FD8"}}},"asOf":"2026-10-08T17:42:10.512Z"}}}},"401":{"description":"The key is missing, malformed, unknown or revoked, or its organization is suspended.","headers":{"WWW-Authenticate":{"description":"Always `Bearer`.","schema":{"type":"string","examples":["Bearer"]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"UNAUTHORIZED","message":"That API key is not valid."}}}}},"404":{"description":"No such event for your organization (unknown, a draft, or someone else's).","content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"NOT_FOUND","message":"No such event."}}}}},"429":{"description":"Too many requests. Wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds to wait before the next request.","required":true,"schema":{"type":"integer","minimum":1,"examples":[12]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests. Slow down."}}}}}}}},"/openapi.json":{"get":{"tags":["Meta"],"operationId":"getOpenApiDocument","summary":"This OpenAPI document","description":"The OpenAPI 3.1 description of this API. No key needed.","security":[],"responses":{"200":{"description":"The OpenAPI document.","headers":{"Cache-Control":{"description":"Cacheable for 5 minutes.","schema":{"type":"string","examples":["public, max-age=300"]}}},"content":{"application/json":{"schema":{"type":"object"}}}},"429":{"description":"Too many requests. Wait `Retry-After` seconds.","headers":{"Retry-After":{"description":"Seconds to wait before the next request.","required":true,"schema":{"type":"integer","minimum":1,"examples":[12]}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ErrorResponse"},"example":{"error":{"code":"RATE_LIMITED","message":"Too many requests. Slow down."}}}}}}}}},"components":{"securitySchemes":{"bearerKey":{"type":"http","scheme":"bearer","bearerFormat":"rc_live_ followed by 32 letters and numbers","description":"An organization API key (rc_live_ plus 32 letters and numbers). Keys default to read-only; legacy keys without scopes remain read-only. Enable Can create events for events:write (create, update, publish), and Can create passes for passes:write (pass import and cancellation). Every valid key can read. Owners and admins make keys under Team & settings, Organization, API. Keep write keys on your server, never in a browser. A new key is shown once."}},"schemas":{"ImportGuest":{"type":"object","required":["externalId","name","ageVerified"],"properties":{"externalId":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"},"name":{"type":"string","minLength":1,"maxLength":60,"description":"Trimmed before use as the pass holder label."},"phone":{"type":"string","description":"A US number, normalized to E.164. Invalid numbers produce a per-guest INVALID error with field phone.","examples":["+17025550111","7025550111"]},"email":{"type":"string","description":"The organizer's contact email."},"ageVerified":{"type":"string","enum":["attested","scanned"]},"waiverAccepted":{"type":"object","required":["version","at"],"properties":{"version":{"type":"string","minLength":1,"maxLength":64},"at":{"type":"string","format":"date-time"}},"additionalProperties":false},"doorNotice":{"type":"string","maxLength":140,"description":"Defaults to Check ID on an age-gated event."},"tags":{"type":"array","maxItems":20,"items":{"type":"string","minLength":1,"maxLength":40}}},"additionalProperties":false},"ImportPassesRequest":{"type":"object","required":["guests"],"properties":{"guests":{"type":"array","minItems":1,"maxItems":100,"items":{"$ref":"#/components/schemas/ImportGuest"}}},"additionalProperties":false},"ImportedPass":{"type":"object","required":["externalId","created","code","qrValue","status"],"properties":{"externalId":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"},"created":{"type":"boolean","description":"True only when this request created the pass."},"code":{"type":"string","pattern":"^[0-9A-HJKMNP-TV-Z]{16}$"},"qrValue":{"type":"string","description":"The signed QR value for a valid pass. Empty for waiver-pending or cancelled passes."},"status":{"type":"string","enum":["valid","waiver","cancelled"]}},"additionalProperties":false},"ImportGuestError":{"type":"object","required":["externalId","error"],"properties":{"externalId":{"type":"string","description":"The supplied ID, or an empty string when it was missing or not a string."},"error":{"type":"object","required":["code"],"properties":{"code":{"type":"string","enum":["INVALID","CAPACITY","INTERNAL"]},"field":{"type":"string","enum":["externalId","name","phone","email","ageVerified","waiverAccepted","doorNotice","tags"]}},"additionalProperties":false}},"additionalProperties":false},"ImportPassesResponse":{"type":"object","required":["passes","asOf"],"properties":{"passes":{"type":"array","minItems":1,"maxItems":100,"items":{"oneOf":[{"$ref":"#/components/schemas/ImportedPass"},{"$ref":"#/components/schemas/ImportGuestError"}]}},"asOf":{"$ref":"#/components/schemas/AsOf"}},"additionalProperties":false},"ImportedPassResponse":{"type":"object","required":["externalId","created","code","qrValue","status","asOf"],"properties":{"externalId":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"},"created":{"type":"boolean","description":"True only when this request created the pass."},"code":{"type":"string","pattern":"^[0-9A-HJKMNP-TV-Z]{16}$"},"qrValue":{"type":"string","description":"The signed QR value for a valid pass. Empty for waiver-pending or cancelled passes."},"status":{"type":"string","enum":["valid","waiver","cancelled"]},"asOf":{"$ref":"#/components/schemas/AsOf"}},"additionalProperties":false},"CheckinEntry":{"type":"object","required":["id","type","at","pass","contact","device","via","reentry","firstCheckIn"],"properties":{"id":{"type":"string","description":"The entry ID. Deduplicate on this value."},"type":{"type":"string","enum":["checkin.in","checkin.out","checkin.undone","walkup.created"]},"at":{"type":"string","format":"date-time","description":"The original scan time, including scans synced later."},"undoes":{"type":"string","description":"The target entry ID for a compensating undo. Absent for legacy undo rows with no target."},"pass":{"type":"object","required":["code","externalId","source","holderLabel"],"properties":{"code":{"type":"string","pattern":"^[0-9A-HJKMNP-TV-Z]{16}$"},"externalId":{"type":["string","null"]},"source":{"type":"string","enum":["rsvp","door","import"]},"holderLabel":{"type":"string"}},"additionalProperties":false},"contact":{"type":"object","required":["phone","email"],"properties":{"phone":{"type":["string","null"]},"email":{"type":["string","null"]}},"additionalProperties":false},"device":{"type":"object","required":["label"],"properties":{"label":{"type":"string"}},"additionalProperties":false},"via":{"type":"string","enum":["scan","list","walkup"]},"reentry":{"type":"boolean","description":"True for an applied arrival after the first check-in."},"firstCheckIn":{"type":"boolean","description":"True for an applied first arrival. False for departures and undo rows."}},"additionalProperties":false},"CheckinsResponse":{"type":"object","required":["entries","nextCursor","asOf"],"properties":{"entries":{"type":"array","maxItems":500,"items":{"$ref":"#/components/schemas/CheckinEntry"}},"nextCursor":{"type":"string","description":"Opaque polling cursor. Always returned, including on empty or short pages. It advances past scanned rows, including unapplied rows omitted from entries."},"asOf":{"$ref":"#/components/schemas/AsOf"}},"additionalProperties":false},"EventCreateRequest":{"type":"object","required":["externalId","title","startsAt","endsAt","timezone"],"properties":{"title":{"type":"string","minLength":1,"maxLength":120,"description":"Trimmed before the shared title validation."},"startsAt":{"type":"string","format":"date-time","description":"ISO timestamp with a UTC offset. Ends after startsAt; at most 14 days total."},"endsAt":{"type":"string","format":"date-time"},"timezone":{"type":"string","description":"An IANA timezone, such as America/Los_Angeles."},"description":{"type":"string","description":"Markdown, normalized exactly like the organizer app (at most 5000 normalized characters)."},"location":{"type":"object","required":[],"properties":{"name":{"type":["string","null"],"maxLength":120},"address":{"type":["string","null"],"maxLength":200},"city":{"type":["string","null"],"maxLength":80},"hidden":{"type":["boolean","null"],"description":"Null resets to false."},"lat":{"type":["number","null"],"minimum":-90,"maximum":90},"lon":{"type":["number","null"],"minimum":-180,"maximum":180}},"additionalProperties":false},"capacity":{"type":["integer","null"],"minimum":1,"description":"Null removes the cap."},"ageGate":{"type":"string","enum":["off","attest","scanOptional","scanRequired"]},"access":{"type":"string","enum":["link","passcode"]},"passcode":{"type":"string","minLength":4,"maxLength":64,"writeOnly":true,"description":"Required when enabling passcode access without an existing passcode. Trimmed; never returned."},"listed":{"type":"boolean","description":"Only link-access events can be listed."},"collectPhone":{"type":"boolean"},"allowReentry":{"type":"boolean"},"externalId":{"type":"string","pattern":"^[A-Za-z0-9_-]{1,64}$"},"publish":{"type":"boolean","default":false}},"additionalProperties":false,"allOf":[{"if":{"properties":{"access":{"const":"passcode"}},"required":["access"]},"then":{"required":["passcode"]}}]},"EventPatchRequest":{"type":"object","required":[],"properties":{"title":{"type":"string","minLength":1,"maxLength":120,"description":"Trimmed before the shared title validation."},"startsAt":{"type":"string","format":"date-time","description":"ISO timestamp with a UTC offset. Ends after startsAt; at most 14 days total."},"endsAt":{"type":"string","format":"date-time"},"timezone":{"type":"string","description":"An IANA timezone, such as America/Los_Angeles."},"description":{"type":"string","description":"Markdown, normalized exactly like the organizer app (at most 5000 normalized characters)."},"location":{"type":"object","required":[],"properties":{"name":{"type":["string","null"],"maxLength":120},"address":{"type":["string","null"],"maxLength":200},"city":{"type":["string","null"],"maxLength":80},"hidden":{"type":["boolean","null"],"description":"Null resets to false."},"lat":{"type":["number","null"],"minimum":-90,"maximum":90},"lon":{"type":["number","null"],"minimum":-180,"maximum":180}},"additionalProperties":false},"capacity":{"type":["integer","null"],"minimum":1,"description":"Null removes the cap."},"ageGate":{"type":"string","enum":["off","attest","scanOptional","scanRequired"]},"access":{"type":"string","enum":["link","passcode"]},"passcode":{"type":"string","minLength":4,"maxLength":64,"writeOnly":true,"description":"Required when enabling passcode access without an existing passcode. Trimmed; never returned."},"listed":{"type":"boolean","description":"Only link-access events can be listed."},"collectPhone":{"type":"boolean"},"allowReentry":{"type":"boolean"}},"additionalProperties":false},"EventWrite":{"type":"object","required":["title","startsAt","endsAt","timezone","venue","coverImageUrl","ageGate","waiver","capacity","counts","rsvpOpen","slug","url","status","access","externalId","description","organization","updates","theme"],"properties":{"title":{"$ref":"#/components/schemas/EventSummary/properties/title"},"startsAt":{"$ref":"#/components/schemas/EventSummary/properties/startsAt"},"endsAt":{"$ref":"#/components/schemas/EventSummary/properties/endsAt"},"timezone":{"$ref":"#/components/schemas/EventSummary/properties/timezone"},"venue":{"$ref":"#/components/schemas/EventSummary/properties/venue"},"coverImageUrl":{"$ref":"#/components/schemas/EventSummary/properties/coverImageUrl"},"ageGate":{"$ref":"#/components/schemas/EventSummary/properties/ageGate"},"waiver":{"$ref":"#/components/schemas/EventSummary/properties/waiver"},"capacity":{"$ref":"#/components/schemas/EventSummary/properties/capacity"},"counts":{"$ref":"#/components/schemas/EventSummary/properties/counts"},"rsvpOpen":{"$ref":"#/components/schemas/EventSummary/properties/rsvpOpen"},"slug":{"type":["string","null"],"description":"Null until published."},"url":{"type":["string","null"],"format":"uri","description":"Public event URL, or null until published."},"status":{"type":"string","enum":["draft","published","cancelled"]},"access":{"type":"string","enum":["link","passcode","invite"],"description":"Invite-only events created in the app can be read and updated, but the API cannot enable invite-only access. Slug-based reads retain EventDetail's password spelling."},"externalId":{"type":["string","null"],"description":"Organization-unique ID, or null for an app-created event without one."},"created":{"type":"boolean","description":"Returned only by create; false for an existing external ID."},"description":{"$ref":"#/components/schemas/RichBody"},"organization":{"$ref":"#/components/schemas/Organization"},"updates":{"type":"array","maxItems":25,"items":{"$ref":"#/components/schemas/HostUpdate"}},"theme":{"$ref":"#/components/schemas/Theme"}},"additionalProperties":false},"EventWriteResponse":{"type":"object","required":["event","asOf"],"properties":{"event":{"$ref":"#/components/schemas/EventWrite"},"asOf":{"$ref":"#/components/schemas/AsOf"}},"additionalProperties":false},"EventByRefResponse":{"anyOf":[{"$ref":"#/components/schemas/EventResponse"},{"$ref":"#/components/schemas/EventWriteResponse"}]},"Venue":{"type":"object","description":"Where the event is. Each field is `null` when not shown. Name and address are `null` when the event hides its location, and when the event is password-protected or invite-only (its public page shows only a teaser until a guest gets in). The city is always shown when set.","required":["name","address","city"],"properties":{"name":{"type":["string","null"],"description":"The venue's name.","examples":["The Rooftop"]},"address":{"type":["string","null"],"description":"The street address.","examples":["123 Main St"]},"city":{"type":["string","null"],"description":"The city.","examples":["Las Vegas"]}}},"Counts":{"type":"object","description":"Guest numbers, the same ones the organizer app shows.","required":["going","reserved","waitlist","spotsLeft"],"properties":{"going":{"type":"integer","minimum":0,"description":"Guests with a pass.","examples":[84]},"reserved":{"type":"integer","minimum":0,"description":"Guests holding a spot who have not finished the steps for a pass yet (a waiver or age check). They are not counted in `going`.","examples":[6]},"waitlist":{"type":"integer","minimum":0,"description":"Guests on the waitlist. Counted up to 100.","examples":[0]},"spotsLeft":{"type":["integer","null"],"minimum":0,"description":"Spots still open, or `null` when the event has no capacity limit.","examples":[30]}}},"EventSummary":{"type":"object","description":"One event as the API shows it.","required":["slug","title","status","startsAt","endsAt","timezone","venue","coverImageUrl","access","ageGate","waiver","capacity","counts","rsvpOpen","url"],"properties":{"slug":{"type":"string","description":"The event's address on Rollcall.","examples":["rooftop-night-k3m9x2q7ab"]},"title":{"type":"string","description":"The event's name.","examples":["Rooftop Night"]},"status":{"type":"string","enum":["published","cancelled"],"description":"`published` or `cancelled`. Drafts are never returned."},"startsAt":{"type":"string","format":"date-time","description":"When the event starts: ISO 8601 with the UTC offset the event's timezone has on that date.","examples":["2026-11-14T21:00:00-08:00"]},"endsAt":{"type":["string","null"],"description":"When the event ends, in the same form as `startsAt`, or `null` if the event has no end.","format":"date-time","examples":["2026-11-15T01:00:00-08:00"]},"timezone":{"type":"string","description":"The event's IANA timezone.","examples":["America/Los_Angeles"]},"venue":{"$ref":"#/components/schemas/Venue"},"coverImageUrl":{"type":["string","null"],"description":"The cover image, or `null` if the event has none.","format":"uri"},"access":{"type":"string","enum":["link","password","invite"],"description":"Who can open the event page: `link` (anyone with the link), `password`, or `invite`."},"ageGate":{"type":"string","enum":["off","attest","scanOptional","scanRequired"],"description":"The age check guests go through: `off` (none), `attest` (guest confirms their age), `scanOptional` or `scanRequired` (ID scan)."},"waiver":{"type":"boolean","description":"`true` if guests sign a waiver."},"capacity":{"type":["integer","null"],"minimum":0,"description":"The guest limit, or `null` for no limit.","examples":[120]},"counts":{"$ref":"#/components/schemas/Counts"},"rsvpOpen":{"type":"boolean","description":"`false` if the event is cancelled or over. A full event still takes RSVPs onto its waitlist, so it stays `true`."},"url":{"type":"string","format":"uri","description":"The Rollcall event page. Send guests here to RSVP.","examples":["https://letsrollcall.com/event/rooftop-night-k3m9x2q7ab"]}},"examples":[{"slug":"rooftop-night-k3m9x2q7ab","title":"Rooftop Night","status":"published","startsAt":"2026-11-14T21:00:00-08:00","endsAt":"2026-11-15T01:00:00-08:00","timezone":"America/Los_Angeles","venue":{"name":"The Rooftop","address":"123 Main St","city":"Las Vegas"},"coverImageUrl":"https://happy-animal-123.convex.cloud/api/storage/6b0c1b6e-0000-4000-8000-000000000000","access":"link","ageGate":"scanOptional","waiver":true,"capacity":120,"counts":{"going":84,"reserved":6,"waitlist":0,"spotsLeft":30},"rsvpOpen":true,"url":"https://letsrollcall.com/event/rooftop-night-k3m9x2q7ab"}]},"EventListResponse":{"type":"object","required":["events","asOf"],"properties":{"events":{"type":"array","maxItems":100,"items":{"$ref":"#/components/schemas/EventSummary"}},"asOf":{"$ref":"#/components/schemas/AsOf"}}},"RichBody":{"type":"object","description":"Rich text in two forms. `html` is the same sanitized markup the Rollcall event page renders: only paragraphs, lists, bold, italic, line breaks and links (links open in a new tab and carry `rel=\"noopener noreferrer nofollow ugc\"`). It is safe to insert as HTML. `text` is the plain-text form for previews and meta descriptions.","required":["html","text"],"properties":{"html":{"type":"string","description":"Sanitized HTML. An empty string when there is none."},"text":{"type":"string","description":"Plain text. An empty string when there is none."}}},"Organization":{"type":"object","description":"The organization that hosts the event, as its public profile shows it.","required":["name","handle","url","avatarUrl"],"properties":{"name":{"type":"string","examples":["Velvet Room"]},"handle":{"type":["string","null"],"description":"The profile handle, or `null` if the organization has none.","examples":["velvet-room"]},"url":{"type":["string","null"],"description":"The organization's public Rollcall profile, or `null` when it has no handle.","format":"uri","examples":["https://letsrollcall.com/velvet-room"]},"avatarUrl":{"type":["string","null"],"description":"The organization's avatar image, or `null` if it has none.","format":"uri"}}},"HostUpdate":{"type":"object","description":"A host update posted on the event page.","required":["postedAt","subject","html","text"],"properties":{"postedAt":{"type":"string","format":"date-time","description":"When the update was posted, in UTC.","examples":["2026-11-12T19:30:00.000Z"]},"subject":{"type":"string","description":"The update's heading, as the page shows it.","examples":["Doors move to 9:30"]},"html":{"type":"string","description":"The update, as sanitized HTML (see `RichBody`)."},"text":{"type":"string","description":"The update, as plain text."}}},"ThemeColors":{"type":"object","description":"The event page's palette: 6-digit hex colors keyed by the names Rollcall uses for them. `bg` is the page background, `text` and `muted` the main and quiet text, `accent` the highlight and `accentText` readable text on top of it, `g1` to `g4` the four colors of the glow behind the page.","required":["bg","text","muted","accent","accentText","g1","g2","g3","g4"],"properties":{"bg":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$","examples":["#0C0614"]},"text":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$","examples":["#0C0614"]},"muted":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$","examples":["#0C0614"]},"accent":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$","examples":["#0C0614"]},"accentText":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$","examples":["#0C0614"]},"g1":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$","examples":["#0C0614"]},"g2":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$","examples":["#0C0614"]},"g3":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$","examples":["#0C0614"]},"g4":{"type":"string","pattern":"^#[0-9a-fA-F]{6}$","examples":["#0C0614"]}}},"Theme":{"type":"object","description":"How the event page looks.","required":["style","colors"],"properties":{"style":{"type":"string","enum":["color","mono"],"description":"`color` when the page uses a palette taken from the cover, `mono` for the plain dark theme the page uses when the event has no custom palette."},"colors":{"oneOf":[{"$ref":"#/components/schemas/ThemeColors"},{"type":"null"}],"description":"The palette, or `null` when the event has none (`style` is then `mono`)."}}},"EventDetail":{"description":"One event in full: every field of `EventSummary` plus the description, the organizer, the host updates and the page's colors. The list endpoint returns summaries only.","allOf":[{"$ref":"#/components/schemas/EventSummary"},{"type":"object","required":["description","organization","updates","theme"],"properties":{"description":{"allOf":[{"$ref":"#/components/schemas/RichBody"}],"description":"The event description, rendered the way the event page renders it. Empty strings when the event has none, and for a password-protected or invite-only event (its page shows no description until a guest gets in)."},"organization":{"$ref":"#/components/schemas/Organization"},"updates":{"type":"array","maxItems":25,"description":"Host updates currently on the event page, newest first, at most 25. Empty when there are none, and for a password-protected or invite-only event.","items":{"$ref":"#/components/schemas/HostUpdate"}},"theme":{"$ref":"#/components/schemas/Theme"}}}],"examples":[{"slug":"rooftop-night-k3m9x2q7ab","title":"Rooftop Night","status":"published","startsAt":"2026-11-14T21:00:00-08:00","endsAt":"2026-11-15T01:00:00-08:00","timezone":"America/Los_Angeles","venue":{"name":"The Rooftop","address":"123 Main St","city":"Las Vegas"},"coverImageUrl":"https://happy-animal-123.convex.cloud/api/storage/6b0c1b6e-0000-4000-8000-000000000000","access":"link","ageGate":"scanOptional","waiver":true,"capacity":120,"counts":{"going":84,"reserved":6,"waitlist":0,"spotsLeft":30},"rsvpOpen":true,"url":"https://letsrollcall.com/event/rooftop-night-k3m9x2q7ab","description":{"html":"<p>Three floors, one rooftop. <strong>Dress to be seen.</strong></p><ul><li><p>Doors at 9</p></li><li><p>Last call at 12:45</p></li></ul>","text":"Three floors, one rooftop. Dress to be seen.\n\n- Doors at 9\n- Last call at 12:45"},"organization":{"name":"Velvet Room","handle":"velvet-room","url":"https://letsrollcall.com/velvet-room","avatarUrl":"https://happy-animal-123.convex.cloud/api/storage/0a1b2c3d-0000-4000-8000-000000000000"},"updates":[{"postedAt":"2026-11-12T19:30:00.000Z","subject":"Doors move to 9:30","html":"<p>Doors now open at 9:30 PM.</p>","text":"Doors now open at 9:30 PM."}],"theme":{"style":"color","colors":{"bg":"#0C0614","text":"#F7ECFF","muted":"#D6C6EC","accent":"#FF4E9C","accentText":"#22000C","g1":"#E0176F","g2":"#2A48FF","g3":"#FF5A1F","g4":"#7B1FD8"}}}]},"EventResponse":{"type":"object","required":["event","asOf"],"properties":{"event":{"$ref":"#/components/schemas/EventDetail"},"asOf":{"$ref":"#/components/schemas/AsOf"}}},"AsOf":{"type":"string","format":"date-time","description":"When we answered, in UTC.","examples":["2026-10-08T17:42:10.512Z"]},"ErrorResponse":{"type":"object","description":"Every error is JSON with a stable `code` and a message meant for people.","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["UNAUTHORIZED","NOT_FOUND","RATE_LIMITED","INVALID","FORBIDDEN","CONFLICT","ORG_SUSPENDED"],"description":"`UNAUTHORIZED` (401), `NOT_FOUND` (404: no such endpoint, or no such event for your organization), `RATE_LIMITED` (429), `INVALID` (400 or 413), `FORBIDDEN` (403: missing required write scope), `CONFLICT` (409), `ORG_SUSPENDED` (403 if suspension races a write)."},"message":{"type":"string","description":"A human-readable explanation."},"field":{"type":"string","description":"The invalid event JSON field, including location.name, location.lat and other nested parts."}}}},"examples":[{"error":{"code":"UNAUTHORIZED","message":"That API key is not valid."}}]},"ApiIndex":{"type":"object","required":["name","version","openapi","docs"],"properties":{"name":{"type":"string","examples":["Rollcall API"]},"version":{"type":"string","examples":["1.0.0"]},"openapi":{"type":"string","format":"uri","description":"Where the OpenAPI document is.","examples":["https://letsrollcall.com/api/v1/openapi.json"]},"docs":{"type":"string","format":"uri","description":"The interactive documentation.","examples":["https://letsrollcall.com/developers"]}}}}}}