Events

Sell tickets to your events, free or paid through Stripe, and check people in at the door with a QR code.

Events lets you publish events and sell tickets to them. Signed-in users pick a ticket on the event page, pay through Stripe Checkout and show a QR code at the door. Staff set up the events, ticket types, add-ons and capacity in the admin area. Use it when your app sells or registers places at dated events. For recurring memberships, use Subscriptions instead.

The package is @frigear-nu/events. Money goes through Payments.

What you get

  • Pages (opt-in): the event list at /events, an event page at /events/:slug, and the signed-in user's tickets at /account/tickets.
  • Admin area (opt-in, with Admin): an event list at /admin/events, and an event page with Details, Tickets and Attendees tabs. With Widget, upcoming events also appear on the admin dashboard.
  • Server routes (on by default): browsing events, buying and paying for tickets, and a staff API for events, attendees, refunds and check-in. The staff API is guarded by the events:manage and events:refundpermissions, which the admin role holds.
  • Composables and helpers (on by default): useEvents, useEvent and useMyTickets.
  • Emails. None built in. Send a confirmation from the events:ticket:paid hook, which runs when a ticket is paid.
  • MCP tools (opt-in): browse events and tickets, and manage events as staff, through MCP.
ServerClientMobile
Installed for you:Stripe, Payments, Auth, Users, MCP, UI and Module Kit. You add:@nuxthub/core (Events turns on its key-value storage), and @nuxt/ui for the pages. Optional:Admin for the admin pages, Subscriptions as the membership provider, Widget for the event page tabs, Menu for menu items, and Account for the navigation around the tickets page.

Quick setup

Install Events

pnpm add @frigear-nu/events @nuxthub/core

Add it to nuxt.config.ts

nuxt.config.ts
export default defineNuxtConfig({
  modules: ['@nuxthub/core', '@frigear-nu/events'],
  events: {
    settings: {
      pages: { events: true, event: true, tickets: true },
      reservationMinutes: 30,
    },
  },
})

Set the Stripe keys

Use Stripe's test keys outside production, and live keys only in production. Keep the secret key and the webhook secret out of the repository.

A ticket becomes paid only from Stripe's verified webhook. Set NUXT_STRIPE_SECRET_KEY, NUXT_STRIPE_WEBHOOK_SECRET and NUXT_PUBLIC_STRIPE_PUBLISHABLE_KEY, and point the webhook at your app, as in Set the Stripe keys.

Generate the migration

Without a migration the event tables do not exist, and every write to them fails.

Events, Payments and Stripe add tables. Generate the migration and commit it:

pnpm db:generate

Decide who manages events

Staff routes check permissions through Authorization. Without a role that holds events:manage, nobody can manage events. The admin role holds it by default.

Give the permissions to the people who run events with a role of your own, or turn on settings.roles for the ready-made eventmanager role:

nuxt.config.ts
export default defineNuxtConfig({
  events: { settings: { roles: true } }, // ships the `eventmanager` role
  authorization: {
    roles: {
      // Roles are built from permissions. `events:*` covers events:manage and events:refund, but not events:pii.
      organiser: { label: 'Organiser', grant: ['events:*', 'events:pii'], inherit: ['user'] },
    },
  },
})

Let staff manage events shows how a route checks them.

What you should see: after staff publish an event, it appears at /events. A ticket bought there redirects to Stripe Checkout, and once paid it shows on /account/tickets as paid.

Options

Options go under the events key.

OptionTypeDefaultPurpose
settings.reservationMinutesnumber30How long an unpaid ticket keeps its seat.
settings.rolesbooleanfalseShips the eventmanager role.
settings.mcpbooleanfalseAdds the module's MCP tools.
settings.pages.eventsstring | booleanoffThe event list. true is /events.
settings.pages.eventstring | booleanoffThe event page. true is /events/:slug.
settings.pages.ticketsstring | booleanoffThe signed-in user's tickets. true is /account/tickets.
settings.pages.adminstring | booleanoffThe staff event list. true is /admin/events.
settings.pages.adminEventstring | booleanoffThe staff event page. true is /admin/events/:id.

settings.reservationMinutes is also the lifetime of the Stripe Checkout session.

settings.pages.* paths keep the parameters of the default, such as :slug.

settings.roles. Registers the eventmanager role with events:manage, events:refund and events:pii, and also puts those three into admin. Without it, only admin holds them, unless your app grants them to a role of its own. Your own authorization.roles.eventmanager merges into the module's role: your label wins, and grant and inherit are added together.

Permissions

Events registers these permissions with Authorization. A staff route calls authorize(event, 'events:manage'); self-service routes call authorize(event, 'tickets:write').

PermissionFlagsHeld by defaultWhat it allows
events:manageadmin, and eventmanager with settings.rolesCreate and edit events, ticket types and add-ons, and check tickets in.
events:refundsessionOnlyadmin, and eventmanagerRefund a paid ticket. Cookie sessions only.
events:piisensitiveadmin, and eventmanagerSensitive (MCP only): gates attendee names and emails in MCP tool output. The admin HTTP API, attendee lists included, is gated by events:manage. A * or events:* grant never covers it: grant it by name.
tickets:readimplicitevery signed-in userRead your own tickets and event details.
tickets:writeimplicitevery signed-in userBuy tickets and pay for them.
  • Scope: tickets (label "Your tickets") expands to tickets:read and tickets:write. A token or OAuth client with it can read and buy the user's own tickets, and is refused every staff route.
  • Roles: eventmanager, shipped only with settings.roles: true.
  • Requirements and policies: none. The module registers no requirement and no policy of its own. Add one with definePolicy when, say, an organiser may only edit their own events.
  • Why events:refund is separate: money moves, so it is session only, and a token can never refund. A role that grants events:manage by name must grant events:refund too (events:* covers both).

See roles and requirements for how roles are built and merged.

Module pages

PageWhat it coversFor
Server APIHow a purchase is checked, sale schedules, membership providers, staff access and MCP tools.App developers and module authors
AppPages, composables, components and extending the admin event page.App developers and module authors
ReferenceHooks, routes, tables and translations.App developers

Next steps

  • Sell event tickets – build the whole flow, from a new event to a paid ticket.
  • Stripe setup – create the keys and the webhook that mark tickets as paid.
  • Server API – limit tickets to members, or connect your own membership list.
Copyright © 2026