{"openapi":"3.1.0","info":{"title":"Callboard Public API","version":"1.0","description":"Callboard's public API. Conventions follow Sessionboard's so an existing\nintegration mostly ports over: `/v1` prefix, event-scoped paths, `POST`\nsearch with a filter body, a `/create` suffix for creates, soft delete +\nrestore, and the `x-access-token` header.\n\nTwo deliberate corrections: ONE response envelope everywhere\n(`{results, pagination}` — Sessionboard returns a different shape for its\nCRUD-proxy GETs), and unassigned metadata is always `null`, never `{}`."},"servers":[{"url":"https://demo.callboardhq.com"}],"security":[{"ApiKeyAuth":[]}],"tags":[{"name":"Events","description":"The entry point for every integration."},{"name":"Sessions","description":"Abstracts and programme sessions — one resource."},{"name":"Speakers","description":"A projection over contacts."},{"name":"Metadata","description":"Tracks, rooms, tags, formats, levels."}],"paths":{"/v1/events":{"get":{"operationId":"listEvents","summary":"List events","description":"Every event the presented key can reach. Keys are minted per event, so this returns exactly one event — the entry point that tells an integration which `eventId` to use everywhere else.","tags":["Events"],"parameters":[{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":999,"default":1}},{"name":"pageSize","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"results":[{"id":"0000000ev-0000-4000-8000-000000000001","name":"Frontier AI Summit 2026","slug":"frontier-ai-summit-2026","timezone":"America/Los_Angeles"}],"pagination":{"currentPage":1,"pageSize":25,"totalPages":1,"totalResults":1}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"x-required-scope":"read:events"}},"/v1/event/{eventId}/sessions/search":{"post":{"operationId":"searchSessions","summary":"Search sessions and abstracts","description":"The workhorse. Abstracts and programme sessions are one resource discriminated by `is_abstract`, so this endpoint serves both 'list the CFP' and 'list the agenda'. `POST /v1/event/{eventId}/sessions` is an alias for wire compatibility with Sessionboard's POST-on-collection search.","tags":["Sessions"],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"},"description":"The event's id. `GET /v1/events` returns the one your key can reach."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"},"example":{"filters":{"status":["accepted","pending"],"is_abstract":true,"text":"agents"},"sort":{"order":"updatedAt","sort":"desc"},"page":1,"pageSize":25}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"results":[{"id":"497f6eca-6276-4993-bfeb-53cbbbba6f08","event_id":"0000000ev-0000-4000-8000-000000000001","friendly_id":"ABS-3","title":"Shipping agents that survive contact with users","status":"accepted","is_abstract":true,"starts_at":null,"ends_at":null,"capacity":null,"is_public":false,"composition_status":{"role":"standalone","is_linked":false,"is_read_only":false,"source_count":0,"target":null},"track":{"id":"…","event_id":"…","name":"Agents","order":0,"color":"#329af0"},"room":null,"participants":[],"custom_fields":[{"key":"takeaways","value":"Three things you can apply Monday."}],"created_at":"2026-07-25T12:00:00.000Z","updated_at":"2026-08-06T12:00:00.000Z","deleted_at":null,"admin_url":"https://callboard.example/admin/submissions/497f6eca-…"}],"pagination":{"currentPage":1,"pageSize":25,"totalPages":1,"totalResults":8}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"x-required-scope":"read:sessions"}},"/v1/event/{eventId}/sessions/{sessionId}":{"get":{"operationId":"getSession","summary":"Get one session","description":"Full record: participants, metadata, composition status, and CFP answers as `custom_fields`.","tags":["Sessions"],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"},"description":"The event's id. `GET /v1/events` returns the one your key can reach."},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"},"description":"Session or abstract id."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"id":"497f6eca-6276-4993-bfeb-53cbbbba6f08","event_id":"0000000ev-0000-4000-8000-000000000001","friendly_id":"ABS-3","title":"Shipping agents that survive contact with users","status":"accepted","is_abstract":true,"starts_at":null,"ends_at":null,"capacity":null,"is_public":false,"composition_status":{"role":"standalone","is_linked":false,"is_read_only":false,"source_count":0,"target":null},"track":{"id":"…","event_id":"…","name":"Agents","order":0,"color":"#329af0"},"room":null,"participants":[],"custom_fields":[{"key":"takeaways","value":"Three things you can apply Monday."}],"created_at":"2026-07-25T12:00:00.000Z","updated_at":"2026-08-06T12:00:00.000Z","deleted_at":null,"admin_url":"https://callboard.example/admin/submissions/497f6eca-…"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scope":"read:sessions"},"put":{"operationId":"updateSession","summary":"Update a session","description":"Partial update. Send the `updated_at` you last read to get optimistic concurrency: a `409` means somebody else wrote first. Omit it to force the write. Flipping `is_public` true requires the speaker's decision letter to have been sent, or `publish_override: true`.","tags":["Sessions"],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"},"description":"The event's id. `GET /v1/events` returns the one your key can reach."},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"},"description":"Session or abstract id."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"},"example":{"status":"accepted","updated_at":"2026-08-06T12:00:00.000Z"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"id":"497f6eca-6276-4993-bfeb-53cbbbba6f08","event_id":"0000000ev-0000-4000-8000-000000000001","friendly_id":"ABS-3","title":"Shipping agents that survive contact with users","status":"accepted","is_abstract":true,"starts_at":null,"ends_at":null,"capacity":null,"is_public":false,"composition_status":{"role":"standalone","is_linked":false,"is_read_only":false,"source_count":0,"target":null},"track":{"id":"…","event_id":"…","name":"Agents","order":0,"color":"#329af0"},"room":null,"participants":[],"custom_fields":[{"key":"takeaways","value":"Three things you can apply Monday."}],"created_at":"2026-07-25T12:00:00.000Z","updated_at":"2026-08-06T12:00:00.000Z","deleted_at":null,"admin_url":"https://callboard.example/admin/submissions/497f6eca-…"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"}},"x-required-scope":"write:sessions"},"delete":{"operationId":"deleteSession","summary":"Soft-delete a session","description":"The row stays and `deleted_at` is set. Deleted rows drop out of search unless you pass `filters.include_deleted`.","tags":["Sessions"],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"},"description":"The event's id. `GET /v1/events` returns the one your key can reach."},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"},"description":"Session or abstract id."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"id":"497f6eca-…","deleted_at":"2026-08-08T18:04:00.000Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scope":"write:sessions"}},"/v1/event/{eventId}/sessions/create":{"post":{"operationId":"createSession","summary":"Create a session or abstract","description":"`title` is the only required field. `is_abstract: true` creates a CFP submission and is immutable afterwards — an abstract never becomes a session, it gets composed into one. `is_public` is update-only.","tags":["Sessions"],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"},"description":"The event's id. `GET /v1/events` returns the one your key can reach."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"},"example":{"title":"Evals that predict production failures","is_abstract":true,"status":"pending","description":"<p>HTML allowed.</p>"}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"id":"497f6eca-6276-4993-bfeb-53cbbbba6f08","event_id":"0000000ev-0000-4000-8000-000000000001","friendly_id":"ABS-3","title":"Shipping agents that survive contact with users","status":"accepted","is_abstract":true,"starts_at":null,"ends_at":null,"capacity":null,"is_public":false,"composition_status":{"role":"standalone","is_linked":false,"is_read_only":false,"source_count":0,"target":null},"track":{"id":"…","event_id":"…","name":"Agents","order":0,"color":"#329af0"},"room":null,"participants":[],"custom_fields":[{"key":"takeaways","value":"Three things you can apply Monday."}],"created_at":"2026-07-25T12:00:00.000Z","updated_at":"2026-08-06T12:00:00.000Z","deleted_at":null,"admin_url":"https://callboard.example/admin/submissions/497f6eca-…"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"x-required-scope":"write:sessions"}},"/v1/event/{eventId}/sessions/{sessionId}/restore":{"post":{"operationId":"restoreSession","summary":"Restore a soft-deleted session","description":"Clears `deleted_at`. 404s if the session was never deleted.","tags":["Sessions"],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"},"description":"The event's id. `GET /v1/events` returns the one your key can reach."},{"name":"sessionId","in":"path","required":true,"schema":{"type":"string"},"description":"Session or abstract id."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"id":"497f6eca-6276-4993-bfeb-53cbbbba6f08","event_id":"0000000ev-0000-4000-8000-000000000001","friendly_id":"ABS-3","title":"Shipping agents that survive contact with users","status":"accepted","is_abstract":true,"starts_at":null,"ends_at":null,"capacity":null,"is_public":false,"composition_status":{"role":"standalone","is_linked":false,"is_read_only":false,"source_count":0,"target":null},"track":{"id":"…","event_id":"…","name":"Agents","order":0,"color":"#329af0"},"room":null,"participants":[],"custom_fields":[{"key":"takeaways","value":"Three things you can apply Monday."}],"created_at":"2026-07-25T12:00:00.000Z","updated_at":"2026-08-06T12:00:00.000Z","deleted_at":null,"admin_url":"https://callboard.example/admin/submissions/497f6eca-…"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scope":"write:sessions"}},"/v1/event/{eventId}/sessions/bulk":{"post":{"operationId":"bulkSessions","summary":"Bulk create / update / delete","description":"Up to 100 operations, applied in order with PARTIAL SUCCESS: each item reports its own status, and one bad row never sinks the batch. The response carries a `batch_id` and a `stats` block.","tags":["Sessions"],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"},"description":"The event's id. `GET /v1/events` returns the one your key can reach."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"},"example":{"operations":[{"action":"create","data":{"title":"Lightning: tool-calling traps"}},{"action":"update","id":"497f6eca-…","data":{"status":"accepted"}},{"action":"delete","id":"8f14e45f-…"}]}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"batch_id":"3f1c…","results":[{"index":0,"action":"create","status":"success","id":"…"},{"index":1,"action":"update","status":"error","error":{"code":"not_found","message":"Session not found."}}],"stats":{"total":2,"succeeded":1,"failed":1}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"x-required-scope":"write:sessions"}},"/v1/event/{eventId}/speakers/search":{"post":{"operationId":"searchSpeakers","summary":"Search speakers","description":"Speakers are a projection over contacts — anyone who is a participant on a live session of this event. `POST /v1/event/{eventId}/speakers` is the compatibility alias.","tags":["Speakers"],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"},"description":"The event's id. `GET /v1/events` returns the one your key can reach."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"},"example":{"filters":{"text":"okafor"},"page":1,"pageSize":25}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"results":[{"id":"…","email":"rina@example.com","full_name":"Rina Okafor","company_name":"Company 1","about":"…","photo_url":null}],"pagination":{"currentPage":1,"pageSize":25,"totalPages":1,"totalResults":8}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"x-required-scope":"read:contacts"}},"/v1/event/{eventId}/speakers/{contactId}":{"get":{"operationId":"getSpeaker","summary":"Get one speaker","description":"The contact record plus `session_ids` — the sessions this person is on, which is what every speaker-portal view needs.","tags":["Speakers"],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"},"description":"The event's id. `GET /v1/events` returns the one your key can reach."},{"name":"contactId","in":"path","required":true,"schema":{"type":"string"},"description":"Contact id (a speaker is a contact)."}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}},"x-required-scope":"read:contacts"}},"/v1/event/{eventId}/{family}":{"get":{"operationId":"listMetadata","summary":"List a metadata family","description":"`family` is one of `tracks`, `rooms`, `tags`, `formats`, `levels`. One generic handler serves all five; `POST` on the same path searches with `filters.text`.","tags":["Metadata"],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"},"description":"The event's id. `GET /v1/events` returns the one your key can reach."},{"name":"family","in":"path","required":true,"schema":{"type":"string","enum":["tracks","rooms","tags","formats","levels"]},"description":"Metadata family: tracks, rooms, tags, formats, levels."},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":999,"default":1}},{"name":"pageSize","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":100,"default":25}}],"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"results":[{"id":"…","event_id":"…","name":"Agents","order":0,"color":"#329af0","created_at":"…","updated_at":"…"}],"pagination":{"currentPage":1,"pageSize":25,"totalPages":1,"totalResults":3}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"x-required-scope":"read:metadata"}},"/v1/event/{eventId}/{family}/create":{"post":{"operationId":"createMetadata","summary":"Create a metadata row","description":"`name` is required. `color` (tracks), `capacity` (rooms) and `default_minutes` (formats) are accepted only on the family that has the column.","tags":["Metadata"],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"},"description":"The event's id. `GET /v1/events` returns the one your key can reach."},{"name":"family","in":"path","required":true,"schema":{"type":"string","enum":["tracks","rooms","tags","formats","levels"]},"description":"Metadata family: tracks, rooms, tags, formats, levels."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"},"example":{"name":"Workshop Room 3","capacity":60}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"x-required-scope":"write:metadata"}},"/v1/event/{eventId}/sessions":{"post":{"operationId":"searchSessionsCompat","summary":"Search sessions (Sessionboard-compatible alias)","description":"The workhorse. Abstracts and programme sessions are one resource discriminated by `is_abstract`, so this endpoint serves both 'list the CFP' and 'list the agenda'. `POST /v1/event/{eventId}/sessions` is an alias for wire compatibility with Sessionboard's POST-on-collection search.","tags":["Sessions"],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"},"description":"The event's id. `GET /v1/events` returns the one your key can reach."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"},"example":{"filters":{"status":["accepted","pending"],"is_abstract":true,"text":"agents"},"sort":{"order":"updatedAt","sort":"desc"},"page":1,"pageSize":25}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"results":[{"id":"497f6eca-6276-4993-bfeb-53cbbbba6f08","event_id":"0000000ev-0000-4000-8000-000000000001","friendly_id":"ABS-3","title":"Shipping agents that survive contact with users","status":"accepted","is_abstract":true,"starts_at":null,"ends_at":null,"capacity":null,"is_public":false,"composition_status":{"role":"standalone","is_linked":false,"is_read_only":false,"source_count":0,"target":null},"track":{"id":"…","event_id":"…","name":"Agents","order":0,"color":"#329af0"},"room":null,"participants":[],"custom_fields":[{"key":"takeaways","value":"Three things you can apply Monday."}],"created_at":"2026-07-25T12:00:00.000Z","updated_at":"2026-08-06T12:00:00.000Z","deleted_at":null,"admin_url":"https://callboard.example/admin/submissions/497f6eca-…"}],"pagination":{"currentPage":1,"pageSize":25,"totalPages":1,"totalResults":8}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"x-required-scope":"read:sessions"}},"/v1/event/{eventId}/speakers":{"post":{"operationId":"searchSpeakersCompat","summary":"Search speakers (Sessionboard-compatible alias)","description":"Speakers are a projection over contacts — anyone who is a participant on a live session of this event. `POST /v1/event/{eventId}/speakers` is the compatibility alias.","tags":["Speakers"],"parameters":[{"name":"eventId","in":"path","required":true,"schema":{"type":"string"},"description":"The event's id. `GET /v1/events` returns the one your key can reach."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object"},"example":{"filters":{"text":"okafor"},"page":1,"pageSize":25}}}},"responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"},"example":{"results":[{"id":"…","email":"rina@example.com","full_name":"Rina Okafor","company_name":"Company 1","about":"…","photo_url":null}],"pagination":{"currentPage":1,"pageSize":25,"totalPages":1,"totalResults":8}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}},"x-required-scope":"read:contacts"}}},"components":{"securitySchemes":{"ApiKeyAuth":{"type":"apiKey","in":"header","name":"x-access-token","description":"Mint one in Admin → API keys. The value is shown once and stored only as a SHA-256 hash. Scopes do not cascade."}},"schemas":{"Error":{"type":"object","required":["error","message"],"properties":{"error":{"type":"string","example":"UnauthorizedError"},"message":{"type":"string"}}},"Pagination":{"type":"object","required":["currentPage","pageSize","totalPages","totalResults"],"properties":{"currentPage":{"type":"integer"},"pageSize":{"type":"integer"},"totalPages":{"type":"integer"},"totalResults":{"type":"integer"}}}},"responses":{"BadRequest":{"description":"Validation failed.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Unauthorized":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Forbidden":{"description":"Wrong event, or the key lacks the required scope.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"No such record in this event.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"Conflict":{"description":"Stale `updated_at` — somebody else wrote first.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"x-scopes":["read:events","read:sessions","write:sessions","read:contacts","read:metadata","write:metadata"]}