docs
/
EventOxygen

Endpoints

The client/events and client/community surfaces the attendee app uses, the auth calls around them, and the chat socket events.

All requests go to EnvironmentConfig.appengineEndpoint. The app token rides in Authorization: Bearer; the customer token rides in x-client-authorization: Bearer on calls made with useUserToken: true. Auth below is what the server enforces: public is @PublicRoute(), customer accepts a customer or staff token.

Auth and profile

POST/profile/app/keyNo auth
POST/profile/customer/signinNo auth
POST/profile/security/challenge/verifyNo auth
POST/profile/customer/signupNo auth
POST/profile/customer/refreshNo auth
GET/profile/customer/profileCUSTOMER
POST/profile/customer/updateCUSTOMER
DELETE/profile/customer/profile/:emailOrUsernameCUSTOMER
GET/profile/customer/password/forgot/:emailNo auth
POST/profile/customer/password/changeCUSTOMER

Sign-in raises TwoFactorRequiredException when the response carries requiresTwoFactor (verify with {challengeToken, code, trustDevice: true}) and PasswordChangeRequiredException when a temporary password is in use. Forgot-password takes ?strategy=temporary_password and emails a temporary password; the app then forces ChangePasswordScreen.

Events and tickets

GET/client/eventsNo auth
GET/client/events/:eventIdNo auth
GET/client/events/:eventId/ticket-typesNo auth
GET/client/events/:eventId/sessionsNo auth
GET/client/events/:eventId/scheduleNo auth
GET/client/events/:eventId/participantsCUSTOMER
GET/client/events/:eventId/mediaNo auth
GET/client/events/tickets/mineCUSTOMER
GET/client/events/tickets/:ticketIdCUSTOMER
GET/client/events/tickets/:ticketId/qrCUSTOMER
GET/client/events/tickets/:ticketId/perksCUSTOMER
POST/client/events/tickets/:ticketId/transferCUSTOMER
GET/client/events/participation/mineCUSTOMER
PUT/client/events/participation/:participantId/respondCUSTOMER

:eventId accepts the slug or the id; the client service resolves it before querying sessions, schedule, participants, ticket types and media. GET /client/events/:eventId returns {event, ticketTypes}. Sessions accept ?day=&track=&type=; participants accept ?type=&role=&page=&limit=. "Assign to someone" and "Transfer" both call the transfer route with {email, name?, reason?}. getSchedule exists in api_service.dart but nothing calls it.

Purchase

POST/client/events/tickets/purchaseNo auth
GET/client/events/stripe/configNo auth
POST/client/events/stripe/intentNo auth
POST/client/events/tickets/confirm-orderNo auth
GET/client/events/bookingNo auth
POST/client/events/tickets/registerCUSTOMER

The flow in _PurchasePage: purchase with {eventId, email, items[], name, paymentMethod: 'stripe' | 'free', promoCode} → a pending booking with data.payment.stripeClientSecret (or a separate intent for {amount, currency: 'usd', referenceId}) → the Stripe payment sheet on device → confirm-order with {bookingId, paymentRef, paymentGateway: 'stripe'}. Free bookings skip straight to issued tickets. Server rules on purchase: ticket type must be active and within its sale window, remaining capacity, maxPerOrder (10), maxPerCustomer (1 for free types) counted across the buyer's live tickets. Confirm refuses a booking that is already paid. Booking lookup takes ?email=&bookingId=.

Community: pages and feed

GET/client/community/pagesNo auth
GET/client/community/pages/:pageIdNo auth
GET/client/community/pages/mineCUSTOMER
POST/client/community/pages/:pageId/joinCUSTOMER
POST/client/community/pages/:pageId/leaveCUSTOMER
GET/client/community/pages/:pageId/announcementsNo auth
GET/client/community/feedNo auth
POST/client/community/postsCUSTOMER
GET/client/community/posts/:postIdNo auth
DELETE/client/community/posts/:postIdCUSTOMER
POST/client/community/posts/:postId/shareCUSTOMER
POST/client/community/posts/:postId/voteCUSTOMER
GET/client/community/posts/:postId/commentsNo auth
POST/client/community/posts/:postId/commentsCUSTOMER
DELETE/client/community/comments/:commentIdCUSTOMER
POST/client/community/reactCUSTOMER
GET/client/community/hashtags/trendingNo auth
GET/client/community/storiesNo auth
POST/client/community/storiesCUSTOMER
POST/client/community/stories/:storyId/viewCUSTOMER

The feed is public on the server but the app sends the customer token so viewerLiked and viewerSaved come back stamped. Query: ?page=&author=&type=&hashtag=&sort=latest|trending|relevant&limit=&pageNum=. react takes {target, targetType, type} and answers {action: 'added' | 'removed' | 'changed'}. Share takes an optional {comment} and creates a post of contentType: 'share'.

Community: people and connections

GET/client/community/people/:emailNo auth
GET/client/community/people/suggestionsCUSTOMER
POST/client/community/connections/requestCUSTOMER
PUT/client/community/connections/:id/respondCUSTOMER
GET/client/community/connectionsCUSTOMER
GET/client/community/connections/pendingCUSTOMER
GET/client/community/connections/sentCUSTOMER
GET/client/community/connections/statsCUSTOMER
POST/client/community/connections/accept-allCUSTOMER
DELETE/client/community/connections/:idCUSTOMER
POST/client/community/followCUSTOMER
DELETE/client/community/follow/:followingIdCUSTOMER
GET/client/community/followersCUSTOMER
GET/client/community/followingCUSTOMER

Request takes {targetId} (an email); respond takes {action: 'accept' | 'reject'} and is allowed only for the target while the request is pending.

Community: messages, notifications, meetings, bookmarks

GET/client/community/messages/threadsCUSTOMER
GET/client/community/messages/thread/:userIdCUSTOMER
POST/client/community/messagesCUSTOMER
POST/client/community/messages/thread/:userId/readCUSTOMER
GET/client/community/messages/unread-countCUSTOMER
GET/client/community/notificationsCUSTOMER
POST/client/community/notifications/readCUSTOMER
GET/client/community/notifications/unread-countCUSTOMER
GET/client/community/meetingsCUSTOMER
GET/client/community/meetings/upcomingCUSTOMER
POST/client/community/meetingsCUSTOMER
PUT/client/community/meetings/:id/respondCUSTOMER
DELETE/client/community/meetings/:idCUSTOMER
GET/client/community/bookmarksCUSTOMER
POST/client/community/bookmarksCUSTOMER
DELETE/client/community/bookmarks/:targetCUSTOMER
POST/client/community/blocksCUSTOMER
POST/client/community/reportsCUSTOMER

Bookmarks take {target, targetType} and are idempotent. Notifications accept ?unread=&type=; mark-read takes {ids: []}.

Media

POST/client/community/media/uploadCUSTOMER
GET/client/community/media/mineCUSTOMER
PUT/client/community/media/renameCUSTOMER
DELETE/client/community/media/:pathCUSTOMER

Uploads are chunked multipart (64 KB chunks, 120 s timeout) from media_upload_service.dart. media/mine?signed=true returns files[].signedUrl, which the service normalizes to url. Files live in the uploader's storage space and are referenced by URL in posts and messages.

Activity

POST/crm/customer-activity/recordNo auth

Sent by activity_tracking_service.dart for screen views, searches and event actions with source: 'app', customerEmail, device and locale fields.

Chat socket

Namespace /community-chat on the appengine host, websocket transport only, handshake auth {token, orgId}.

DirectionEvents
Client emitssendMessage, sendGroupMessage, typing, groupTyping, markRead, getOnlineUsers, joinGroup, leaveGroup
Server pushesmessage, groupMessage, typing, onlineStatus, error

When the socket is down, ChatScreen sends over POST /client/community/messages instead, so nothing is lost; it just arrives without the live typing and delivery updates.

Staff-side counterpart

Scanning, accreditation, badges, credentials and ticket administration live on the staff-only /events controller used by Appmint Mobile; see Appmint Mobile endpoints. The /community admin controller mirrors the client connections, messages, meetings, blocks and reports routes without the client/ prefix.