Events are first-class records in the event collection. Staff create them through the standard data API (POST /repository/create/event/create) and use the /events/* routes for lifecycle operations like publishing and managing capacity.
Endpoints
/repository/create/eventJWT/eventsJWT/events/:idJWT/events/:id/publishJWT/client/eventsNo auth/client/events/:eventIdNo authEvent shape
type Event = {
pk: string;
sk: string;
datatype: 'event';
state: 'draft' | 'published' | 'live' | 'ended' | 'cancelled';
data: {
name: string;
slug: string;
description?: string;
type: 'conference' | 'workshop' | 'concert' | 'meetup' | string;
status: 'draft' | 'published' | 'live' | 'ended';
startDate: string; // ISO 8601
endDate: string;
timezone: string; // e.g. 'America/New_York'
venue?: {
name: string;
address?: string;
city?: string;
country?: string;
lat?: number;
lng?: number;
capacity?: number;
};
onlineUrl?: string; // for hybrid/virtual
image?: string;
coverImage?: string;
capacity?: number; // overall cap; per-type caps live on TicketType
scanPoints?: ScanPoint[]; // doors/zones for check-in
settings?: {
allowReentry?: boolean;
requireCheckIn?: boolean;
sendEventReminders?: boolean;
publicSchedule?: boolean;
};
organizer?: { name: string; email: string; phone?: string };
tags?: string[];
};
};
Creating an event
await fetch('/repository/create/event', {
method: 'POST',
headers: {
orgid: 'my-org',
Authorization: `Bearer ${jwt}`,
'Content-Type': 'application/json',
},
body: JSON.stringify({
data: {
name: 'TypeFest 2026',
slug: 'typefest-2026',
type: 'conference',
status: 'draft',
startDate: '2026-09-12T09:00:00Z',
endDate: '2026-09-14T18:00:00Z',
timezone: 'America/New_York',
venue: {
name: 'Brooklyn Expo',
address: '72 Noble St',
city: 'Brooklyn',
country: 'US',
capacity: 1200,
},
organizer: { name: 'AppMint', email: '[email protected]' },
},
}),
});
The repository fires a COLLECTION_CREATE event that the EventService listens to — it initialises the stats counters, generates per-day slot records (used by the schedule view), and notifies any pre-existing ticket holders if the event was duplicated from a template.
Publishing
Drafts are invisible to customer-side endpoints. Publish flips the state and emits a notification to subscribers.
await fetch(`/events/${eventId}/publish`, {
method: 'POST',
headers: { orgid: 'my-org', Authorization: `Bearer ${jwt}` },
});
Server-side, publish does three things:
- Validates the event has at least one published
TicketType(events without sellable tickets stay private). - Sets
data.statustopublishedand the wrapperstatetopublished. - Triggers a Sync notification job using the
event-publishedtemplate, fanning out to anyone who pre-registered interest.
Listing and filtering
GET /events accepts status, type, fromDate, toDate, limit, offset. The customer-facing GET /client/events mirrors the same shape but only returns events with status: 'published' or live.
const upcoming = await fetch(
'/client/events?fromDate=2026-04-01&type=conference&limit=20',
{ headers: { orgid: 'my-org' } }
).then(r => r.json());
Scan points
scanPoints is an array of named entry/exit points used at check-in. Each scan point declares which ticket types it accepts and what to match the QR payload against.
scanPoints: [
{
id: 'main-door',
name: 'Main entrance',
zone: 'venue',
matchField: 'qrCode', // 'qrCode' | 'credentialCode' | 'ticketId'
acceptedTicketTypes: ['general', 'vip'],
direction: 'both', // 'in' | 'out' | 'both'
},
{
id: 'vip-lounge',
name: 'VIP lounge',
zone: 'vip',
matchField: 'qrCode',
acceptedTicketTypes: ['vip'],
direction: 'in',
},
];
Scan points are referenced by checkpoint in the check-in flow.
Capacity
data.capacity is the global cap. Per-type caps go on TicketType.capacity. The check-in service tracks zone occupancy in real time using the scan-in events and exposes it at GET /events/:eventId/occupancy.
The capacity field is checked at ticket-issue time but is not a hard atomic guard. If you're running a sale that will burst past capacity in seconds, also set data.capacityHard: true to enable the optimistic-locking path on issue.