Events

Events reference

Look up the hooks, HTTP routes, database tables and translation keys of Events.

This page lists what Events adds to your server: hooks, routes, tables and translations. It is for app developers and module authors. Set up the module first: Overview.

Hooks

Your app answers these Nitro hooks from a server plugin (server/plugins/*.ts).

HookWhenPayload
events:purchase:beforeDuring a purchase, after the capacity checks. Throw to deny.PurchaseBeforeContext
events:ticket:paidA ticket became paid, or a free ticket was issued. Send confirmations here.TicketHookContext
events:ticket:refundedA ticket was fully refunded.TicketHookContext
events:membership:checkA membership requirement is checked.MembershipCheckContext
events:membership:optionsThe admin area asks which memberships can be picked.MembershipOptionsContext
type PurchaseBeforeContext = { event: H3Event, userId: number, eventId: string, ticketTypeId: string, addonIds: string[] }
type TicketHookContext = { ticket: TicketDto }
type MembershipCheckContext = { userId: number, requirement: 'any' | string[], satisfied: boolean }
type MembershipOptionsContext = { available: boolean, options: Array<{ value: string, label: string }> }

A membership rule (requiresMembership, excludesMembership) is null for nobody, 'any' for any active membership, or a list of membership keys.

Routes

Routes the module registers, and who may call them. Public and self-service routes are under /api/events, and staff routes under /api/admin/events. Build the paths with eventsApi from @frigear-nu/events/api, for example eventsApi.admin.event(id).

  • Permissions. A row names the permission the route checks with authorize. A token also needs a scope that covers it, as Access control explains.
  • Staff means the caller holds events:manage through a role. See Let staff manage events.
  • Errors carry a snake_case data.code, such as not_found or conflict. Validation failures are h3's 400.
MethodPathAuthStatusPurpose
GET/api/eventspublic200Published events.
GET/api/events/:slugpublic (optional tickets:read)200One event. Signed in, each ticket type carries a blocked reason.
POST/api/events/:slug/purchasetickets:write200Buy a ticket: { ticket, url? }.
GET/api/events/me/ticketstickets:read200The caller's tickets.
GET/api/events/me/tickets/:idtickets:read200One of the caller's tickets, to poll after returning from Stripe.
POST/api/events/me/tickets/:id/paytickets:write200Resume paying a pending ticket: { url }.
GET/api/admin/eventsevents:manage200Events, paginated. Query parameters below.
POST/api/admin/eventsevents:manage201Create an event, with its whole catalogue if given.
GET/api/admin/events/:idevents:manage200One event, whatever its status, with all ticket types, add-on groups and add-ons.
PATCH/api/admin/events/:idevents:manage200Update an event. 409 conflict for a taken slug.
DELETE/api/admin/events/:idevents:manage204Delete an event. 409 when it has paid tickets: archive it instead.
POST/api/admin/events/:id/cloneevents:manage201Copy into a new draft (<slug>-copy, -copy-2, …). Dates stay, and tickets are not copied.
GET/api/admin/events/:id/ticketsevents:manage200Attendees, paginated, with each QR code. Query parameters below.
POST/api/admin/events/:id/ticket-typesevents:manage201Add a ticket type. 404 for an unknown event, 409 for a taken key.
PATCH/api/admin/events/ticket-types/:idevents:manage200Update a ticket type.
DELETE/api/admin/events/ticket-types/:idevents:manage204Delete a ticket type. 409 while it has active tickets.
POST/api/admin/events/ticket-types/:id/addon-groupsevents:manage201Add an add-on group. 404 for an unknown ticket type.
PATCH/api/admin/events/addon-groups/:idevents:manage200Update an add-on group.
DELETE/api/admin/events/addon-groups/:idevents:manage204Delete an add-on group and its add-ons.
POST/api/admin/events/addon-groups/:id/addonsevents:manage201Add an add-on. 404 for an unknown group.
PATCH/api/admin/events/addons/:idevents:manage200Update an add-on.
DELETE/api/admin/events/addons/:idevents:manage204Delete an add-on.
POST/api/admin/events/tickets/:id/cancelevents:manage200Cancel an unpaid or free ticket. Answers the attendee.
POST/api/admin/events/tickets/:id/refundevents:refund200Start a full refund of a paid ticket.
GET/api/admin/events/membership-optionsevents:manage200{ available, options } from the membership provider.
GET/api/admin/events/upcomingevents:manage200{ total, items }: the next published events, for the admin dashboard.
POST/api/admin/events/check-inevents:manage200Check a ticket in. Body { code }.

GET /api/admin/events takes page, pageSize (at most 100), q (the name in any language, or the slug), status, sort (startsAt, createdAt, slug or status) and order. It answers { items, total, page, pageSize }.

GET /api/admin/events/:id/tickets takes q (the holder's name or email), status and sort (createdAt, status, checkedInAt, name or email).

POST /api/admin/events/tickets/:id/refund moves money, so events:refund is a session-only permission. A token gets 403 session_required. Only a paid ticket with a payment can be refunded.

Deletes answer 404 not_found when the row does not exist. Static segments such as me, upcoming and check-in win over :slug and :id.

Database

Tables the module adds. Generate and commit a migration after installing. Payments, Users and Subscriptions need theirs too.

TableHolds
eventsTranslated name, description and body, the place, startsAt / endsAt, status (draft, published, archived) and requiresMembership.
event_ticket_typesPer event: a unique key, price (0 is free), currency (default DKK), capacity, the sale window and schedule, maxPerUser (default 1) and membership rules.
event_addon_groupsPer ticket type, such as "Food": required, multiple and sortOrder.
event_addonsThe choices in a group: label, price, an optional capacity and sortOrder.
event_ticketsstatus (pending, paid, cancelled, refunded, expired), the add-ons, amount and currency bought, paymentId, the unique QR code, locale and check-in.

Translated texts are a string or a { da, en } map.

Translations

Override any string in your app's i18n/locales/<code>.json. The module registers da and en files under events.*. See overriding module strings. Without @nuxtjs/i18n, the pages use en.

{ "events": { "upcoming": { "title": "What's on" } } }

Key groups: upcoming.*, ongoing.*, past.*, detail.* (with the purchase flow), tickets.* (with tickets.status.*), cart.*, menu.* and admin.* (with admin.tabs.* and admin.statuses.*). Top-level keys include title, empty, loading, ticketReady, paymentReceived and purchaseFailed.

Next steps

  • Server API – the purchase checks behind these routes.
  • Send an email – send the ticket confirmation from events:ticket:paid.
  • Payments – the payments:* hooks and refunds behind a ticket's status.
Copyright © 2026