Documentation

Event creation

Create the event record, set up venues and capacity, and publish.

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

POST/repository/create/eventJWT
GET/eventsJWT
GET/events/:idJWT
POST/events/:id/publishJWT
GET/client/eventsNo auth
GET/client/events/:eventIdNo auth

Event 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:

  1. Validates the event has at least one published TicketType (events without sellable tickets stay private).
  2. Sets data.status to published and the wrapper state to published.
  3. Triggers a Sync notification job using the event-published template, 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.

Capacity is advisory at sell time

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.