Technical Reference
Events

Events — Technical Reference

This page covers the data models, background sync engines, Eventbrite webhook handlers, and public APIs behind the Events module.


Data Models

events

Stores event records from both manual and external Eventbrite sources.

ColumnTypeDescription
iduuidPrimary key
workspace_iduuidTenant isolation — FK → workspaces.id (ON DELETE CASCADE)
nametextInternal event name
descriptiontextRich-text HTML event description
locationtextPhysical location or "Online"
start_timetimestamptzStart time (stored in UTC)
end_timetimestamptzEnd time (stored in UTC)
timezonetextIANA timezone string (e.g., America/Chicago)
external_event_idtextEventbrite event ID, or NULL for manual events
is_publishedbooleanFlag to display event on public RSVP page / API (default false)
website_titletextOptional public heading (falls back to name)
website_descriptiontextOptional public description (falls back to description)
ticket_pricenumeric(10,2)Lowest paid ticket price, tax-inclusive
ticket_class_countintegerNumber of paid ticket types
eventbrite_urltextDirect link to the Eventbrite event page
last_synced_attimestamptzTimestamp of the last Eventbrite sync
created_attimestamptzRecord creation timestamp
updated_attimestamptzLast updated timestamp

event_registrations

Logs contact RSVPs and tickets.

ColumnTypeDescription
iduuidPrimary key
workspace_iduuidTenant isolation — FK → workspaces.id (ON DELETE CASCADE)
event_iduuidAssociated event — FK → events.id (ON DELETE CASCADE)
contact_iduuidMatched contact — FK → contacts.id (ON DELETE CASCADE)
amount_paidnumeric(10,2)Ticket price paid
statustext'registered' or 'cancelled'
external_attendee_idtextUnique Eventbrite attendee ID
created_attimestamptzRecord creation timestamp
updated_attimestamptzLast updated timestamp

eventbrite_connections

Stores credentials for workspace Eventbrite integrations.

ColumnTypeDescription
iduuidPrimary key
workspace_iduuidTenant isolation — FK → workspaces.id (ON DELETE CASCADE), unique
access_tokentextOAuth access credentials
organization_idtextLinked Eventbrite organization ID
organization_nametextName of the organization
webhook_idtextEventbrite webhook subscription identifier
auto_subscribe_attendeesbooleanFlag to auto-subscribe webhook registrants
connected_attimestamptzWhen the connection was established
updated_attimestamptzLast updated timestamp

Integrations & Sync Engines

OAuth Connection Flow

The connection is established via the standard OAuth 2.0 flow:

  1. Redirects user to Eventbrite authorization.
  2. Callback endpoint /api/auth/eventbrite/callback exchanges authorization codes for long-lived access tokens.
  3. Queries Eventbrite API to discover the Organization ID.
  4. Registers an organization-level webhook on Eventbrite for events order.placed, order.refunded, and attendee.updated.
  5. Persists tokens in eventbrite_connections.

Eventbrite Ticket Ingestion

Ticket pricing is derived dynamically during imports or sync events:

  • Checks the ticket_classes array of the Eventbrite event.
  • Extracts (cost + tax + fee) / 100 (buyer-facing total price) to find the lowest paid ticket option.
  • Stores the total count of paid ticket classes as ticket_class_count.

Webhook Sync Engine

Real-time attendee updates route to:

POST /api/webhooks/eventbrite

Background Processing

The webhook handler responds with HTTP 200 immediately to prevent Eventbrite retry timeouts. Processing runs asynchronously in the background using the Next.js after() API.

Webhook Event Actions

1. order.placed

  • Fetches order details expanded with attendee lists.
  • Matches external_event_id to resolve the target CRM event.
  • Upserts contact profiles matching email. If email is blank (e.g. "Info requested"), falls back to the buyer's details.
  • Inserts event_registrations rows mapping external_attendee_id (idempotent unique index).
  • Auto-subscribes the contact (setting is_subscribed = true, opt_in_source = 'eventbrite_auto_subscribe', and clearing non-complaint suppressions) if auto_subscribe_attendees is enabled.
  • Fires event_registration automations (deduplicated in-memory to execute once per contact).

2. attendee.updated (Transfers & Details Updates)

  • If the ticket email changes (transfer), creates a new contact, updates the contact_id on the registration, and fires the registration automation rules. If auto_subscribe_attendees is enabled, the new contact is also auto-subscribed.
  • If only name details change, updates the contact record.

3. order.refunded (Cancellation)

  • Sets the registration status to 'cancelled' and zeroes amount_paid.
  • Queries total active tickets for the contact. If the count reaches 0, cancels any active campaign enrollments linked to that event.

Server Actions

getEvents

The getEvents server action retrieves a paginated list of events for the active workspace, applying search and status filters.

export interface EventListParams {
    page?: number;
    pageSize?: number;
    search?: string;
    upcoming?: boolean | null;
    published?: boolean | null;
    sortBy?: string;
    sortDir?: "asc" | "desc";
}

Filtering & Sorting Parameters:

  • upcoming: Tri-state time filter (incorporating live/ongoing events):
    • true: Retrieves upcoming and active events (where the event has not concluded: start_time >= NOW() or end_time >= NOW()).
    • false: Retrieves concluded past events (where end_time < NOW(), or if no end time is specified, start_time < NOW()).
    • null / undefined: Retrieves all events.
  • published: Tri-state publishing filter:
    • true: Filters for published events (is_published = true).
    • false: Filters for unpublished events (is_published = false or NULL).
    • null / undefined: Bypasses publishing restrictions and returns both.
  • sortBy: Specifies the column to sort by. Supported values:
    • "name": Sorts alphabetically by event name (name).
    • "created_at": Sorts by event record creation date.
    • "start_time" (default): Sorts chronologically by event start date (start_time).
  • sortDir: The sort direction ("asc" or "desc").
  • search: Optional text string. Filters name or location using a case-insensitive SQL ilike partial match (%search%).

Public APIs

1. RSVP Page Validation Flow

The hosted RSVP page (/rsvp/[eventId]) performs checks before rendering the registration form:

  • Validates the event UUID exists in the workspace.
  • Enforces is_published = true.
  • Rejects requests if start_time is in the past.
  • Rejects if external_event_id is present (directing users to the Eventbrite listing).

2. Contact Upsert Rules

The RSVP page API (POST /api/rsvp/[eventId]) applies the following contact update policies:

  • New Contact: Creates a contact profile setting source = 'event' and marketing consent variables.
  • Existing Contact: Updates consent parameters (is_subscribed, opt_in_timestamp, opt_in_source, opt_in_ip), clears unsubscribed_at, and clears non-complaint suppressions. It never overwrites existing contact names.

3. Headless Events API

Retrieves published schedules:

GET /api/v1/public/events
  • Authenticates using the Bearer token or ?key= query.
  • Returns JSON array of events where is_published = true and end_time > UTC_NOW().
  • Sorts ascending by start_time.
  • Adds Access-Control-Allow-Origin: * to CORS headers.
  • Each event object includes pricing fields:
    • ticket_class_count (integer): Number of paid ticket classes.
    • display_price (string): pre-computed display price string (e.g. "Free", "From $15.00", or "$30.00").

Performance & Hydration Optimization

Server-Side Pre-fetching & Lazy Loading

  • Server Component (pages/events/page.tsx): Pre-fetches the active workspace, page 1 events list, and Eventbrite integration status in parallel on the server.
  • Client Component (events-client.tsx): Coordinates tabular list rendering, pagination, sorting columns, and segmented filters (Time and Website).
  • Dynamic imports: Dynamically imports and lazy loads heavy creation dialogs (CreateEventDialog and ImportEventbriteDialog) with ssr: false.
  • Sync Gates: Uses isFirstQueryRef to prevent initial mounting waterfalls and initialWorkspaceIdRef state synchronization hook.

Row-Level Security (RLS)

All tables enforce tenant-level isolation using the get_user_workspace_ids() helper.

TableSELECTINSERTUPDATEDELETE
eventsWorkspace membersAdmin+Admin+Admin+
event_registrationsWorkspace membersSystem APISystem APIAdmin+
eventbrite_connectionsWorkspace membersAdmin+Admin+Admin+