A session is a scheduled item on an event's agenda — a keynote, a workshop, a panel, a break. Sessions live in their own collection (event_session) so multi-day, multi-track events can carry a full conference programme. The Events module gives you per-event session CRUD plus a shaped schedule endpoint that groups sessions by day for direct rendering in a programme view.
Endpoints
/events/:eventId/sessionsJWT/events/:eventId/sessionsJWT/events/:eventId/scheduleJWT/events/sessions/:sessionIdJWT/events/sessions/:sessionIdJWT/client/events/:eventId/sessionsNo auth/client/events/:eventId/scheduleNo authSession shape
type Session = {
pk: string;
sk: string;
datatype: 'event_session';
data: {
event: string; // eventId
title: string;
description?: string;
type: 'talk' | 'workshop' | 'panel' | 'break' | 'networking' | string;
track?: string; // e.g. 'design', 'engineering'
room?: string; // physical room name
day?: string; // 'YYYY-MM-DD'; auto-derived from startTime if omitted
startTime: string; // ISO 8601
endTime: string;
capacity?: number;
speakers?: Array<{ email: string; name: string; bio?: string; image?: string }>;
requiresTicket?: boolean;
requiredTicketTypes?: string[];
status: 'scheduled' | 'live' | 'ended' | 'cancelled';
streamUrl?: string; // virtual/hybrid
recordingUrl?: string;
};
};
Creating a session
await fetch(`/events/${eventId}/sessions`, {
method: 'POST',
headers: {
orgid: 'my-org',
Authorization: `Bearer ${jwt}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
title: 'The state of variable fonts',
type: 'talk',
track: 'typography',
room: 'Hall A',
startTime: '2026-09-12T10:00:00Z',
endTime: '2026-09-12T11:00:00Z',
speakers: [
{ email: '[email protected]', name: 'Alice Lee' },
],
requiresTicket: true,
requiredTicketTypes: ['general', 'vip'],
}),
});
The service derives day from startTime (in the event's timezone) so the schedule grouping is consistent.
Listing sessions
GET /events/:eventId/sessions accepts day (YYYY-MM-DD), track, type, and status. Use this when you want a flat list with custom filtering.
const sessions = await fetch(
`/client/events/${eventId}/sessions?day=2026-09-12&track=typography`,
{ headers: { orgid: 'my-org' } }
).then(r => r.json());
Schedule endpoint
GET /events/:eventId/schedule returns sessions pre-grouped by day, sorted by start time, with the room/track structure flattened for direct rendering:
{
"days": [
{
"day": "2026-09-12",
"sessions": [
{ "id": "...", "title": "...", "startTime": "...", "endTime": "...", "track": "...", "room": "..." }
]
},
{ "day": "2026-09-13", "sessions": [...] }
]
}
Use this on a public event page to render a tabbed day-by-day programme without doing the grouping yourself.
Updating and deleting
// Update — partial body merged into data
await fetch(`/events/sessions/${sessionId}`, {
method: 'PUT',
headers: { orgid: 'my-org', Authorization: `Bearer ${jwt}`, 'Content-Type': 'application/json' },
body: JSON.stringify({ room: 'Hall B', status: 'scheduled' }),
});
// Delete
await fetch(`/events/sessions/${sessionId}`, {
method: 'DELETE',
headers: { orgid: 'my-org', Authorization: `Bearer ${jwt}` },
});
Cancelling (status: 'cancelled') is the soft path — keeps the record so attendees who saved the session see "cancelled" instead of a 404. Hard delete is for genuine removal during planning.
Linking sessions to check-in
A session can be referenced from a check-in scan by passing sessionId to POST /events/checkin. This records per-session attendance and lets you compute "who actually came to the keynote" rather than just who walked through the front door. See Check-in.
Sessions don't sell tickets on their own. If a session is gated, set requiresTicket: true and list the qualifying requiredTicketTypes — the check-in service rejects scans for non-qualifying ticket types at session scan points.