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
/profile/app/keyNo auth/profile/customer/signinNo auth/profile/security/challenge/verifyNo auth/profile/customer/signupNo auth/profile/customer/refreshNo auth/profile/customer/profileCUSTOMER/profile/customer/updateCUSTOMER/profile/customer/profile/:emailOrUsernameCUSTOMER/profile/customer/password/forgot/:emailNo auth/profile/customer/password/changeCUSTOMERSign-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
/client/eventsNo auth/client/events/:eventIdNo auth/client/events/:eventId/ticket-typesNo auth/client/events/:eventId/sessionsNo auth/client/events/:eventId/scheduleNo auth/client/events/:eventId/participantsCUSTOMER/client/events/:eventId/mediaNo auth/client/events/tickets/mineCUSTOMER/client/events/tickets/:ticketIdCUSTOMER/client/events/tickets/:ticketId/qrCUSTOMER/client/events/tickets/:ticketId/perksCUSTOMER/client/events/tickets/:ticketId/transferCUSTOMER/client/events/participation/mineCUSTOMER/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
/client/events/tickets/purchaseNo auth/client/events/stripe/configNo auth/client/events/stripe/intentNo auth/client/events/tickets/confirm-orderNo auth/client/events/bookingNo auth/client/events/tickets/registerCUSTOMERThe 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
/client/community/pagesNo auth/client/community/pages/:pageIdNo auth/client/community/pages/mineCUSTOMER/client/community/pages/:pageId/joinCUSTOMER/client/community/pages/:pageId/leaveCUSTOMER/client/community/pages/:pageId/announcementsNo auth/client/community/feedNo auth/client/community/postsCUSTOMER/client/community/posts/:postIdNo auth/client/community/posts/:postIdCUSTOMER/client/community/posts/:postId/shareCUSTOMER/client/community/posts/:postId/voteCUSTOMER/client/community/posts/:postId/commentsNo auth/client/community/posts/:postId/commentsCUSTOMER/client/community/comments/:commentIdCUSTOMER/client/community/reactCUSTOMER/client/community/hashtags/trendingNo auth/client/community/storiesNo auth/client/community/storiesCUSTOMER/client/community/stories/:storyId/viewCUSTOMERThe 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
/client/community/people/:emailNo auth/client/community/people/suggestionsCUSTOMER/client/community/connections/requestCUSTOMER/client/community/connections/:id/respondCUSTOMER/client/community/connectionsCUSTOMER/client/community/connections/pendingCUSTOMER/client/community/connections/sentCUSTOMER/client/community/connections/statsCUSTOMER/client/community/connections/accept-allCUSTOMER/client/community/connections/:idCUSTOMER/client/community/followCUSTOMER/client/community/follow/:followingIdCUSTOMER/client/community/followersCUSTOMER/client/community/followingCUSTOMERRequest 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
/client/community/messages/threadsCUSTOMER/client/community/messages/thread/:userIdCUSTOMER/client/community/messagesCUSTOMER/client/community/messages/thread/:userId/readCUSTOMER/client/community/messages/unread-countCUSTOMER/client/community/notificationsCUSTOMER/client/community/notifications/readCUSTOMER/client/community/notifications/unread-countCUSTOMER/client/community/meetingsCUSTOMER/client/community/meetings/upcomingCUSTOMER/client/community/meetingsCUSTOMER/client/community/meetings/:id/respondCUSTOMER/client/community/meetings/:idCUSTOMER/client/community/bookmarksCUSTOMER/client/community/bookmarksCUSTOMER/client/community/bookmarks/:targetCUSTOMER/client/community/blocksCUSTOMER/client/community/reportsCUSTOMERBookmarks take {target, targetType} and are idempotent. Notifications accept ?unread=&type=; mark-read takes {ids: []}.
Media
/client/community/media/uploadCUSTOMER/client/community/media/mineCUSTOMER/client/community/media/renameCUSTOMER/client/community/media/:pathCUSTOMERUploads 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
/crm/customer-activity/recordNo authSent 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}.
| Direction | Events |
|---|---|
| Client emits | sendMessage, sendGroupMessage, typing, groupTyping, markRead, getOnlineUsers, joinGroup, leaveGroup |
| Server pushes | message, 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.