Attendance Analytics API
Base URL: https://api.nexgate.com/api/v1
Short Description: The Attendance Management API provides comprehensive attendee tracking and analytics for event organizers. Organizers can view overall attendance statistics with per-day and per-ticket-type breakdowns, browse a unified attendance list (present, absent, and partially attended in one view) with rich filtering, and drill into the full check-in history for any individual ticket. The system supports single-day and multi-day events. All status filtering, day filtering, buyer-type filtering, and search are handled through query parameters on a single list endpoint.
Hints:
- Organizer Only: All endpoints restricted to the event organizer
- Unified List: Present and absent tickets are in one list — filter with
?status=PRESENT|ABSENT|PARTIALLY_ATTENDED - Ticket-Based: Each row in the list is one ticket, not one person — one buyer can appear multiple times
- Attendee Number: Each ticket has a unique
attendeeNumber=bookingReference + "-" + ticketSeries(e.g.EVT-A3F4B21C-VIP-0042) - Buyer vs Attendee:
buyer= who paid,attendee= who holds the ticket — can be different people - Buyer Types:
SYSTEM_USER= bought online,AT_DOOR= name captured at door (no account) - Multi-Day Support: Per-day filtering via
?dayNumber=1— optional, omit for overall view - Partial Attendance:
PARTIALLY_ATTENDED= checked in some days but not all (multi-day events only) - Pagination: Default 20 per page
Response Structures
AttendanceSummaryResponse
Returned by GET /summary. Always covers the full event — no filtering.
{
"eventId": "uuid",
"eventTitle": "East African Tech Summit 2026",
"totalDays": 3,
"eventSchedule": [
{ "dayNumber": 1, "dayName": "Day 1 - Opening", "date": "2026-12-15" },
{ "dayNumber": 2, "dayName": "Day 2 - Conference", "date": "2026-12-16" },
{ "dayNumber": 3, "dayName": "Day 3 - Closing", "date": "2026-12-17" }
],
"overallStats": {
"totalTickets": 500,
"present": 310,
"partiallyAttended": 45,
"absent": 145,
"attendanceRate": 71.0,
"byDay": [
{
"dayNumber": 1,
"dayName": "Day 1 - Opening",
"date": "2026-12-15",
"totalTickets": 500,
"checkedIn": 400,
"absent": 100,
"attendanceRate": 80.0,
"status": "COMPLETED"
},
{
"dayNumber": 2,
"dayName": "Day 2 - Conference",
"date": "2026-12-16",
"totalTickets": 500,
"checkedIn": 355,
"absent": 145,
"attendanceRate": 71.0,
"status": "ONGOING"
},
{
"dayNumber": 3,
"dayName": "Day 3 - Closing",
"date": "2026-12-17",
"totalTickets": 500,
"checkedIn": 0,
"absent": 500,
"attendanceRate": 0.0,
"status": "UPCOMING"
}
]
},
"byTicketType": [
{
"ticketTypeId": "uuid",
"ticketTypeName": "VIP Pass",
"totalSold": 100,
"present": 75,
"partiallyAttended": 10,
"absent": 15,
"attendanceRate": 85.0,
"byDay": [
{
"dayNumber": 1,
"dayName": "Day 1 - Opening",
"checkedIn": 90,
"absent": 10,
"attendanceRate": 90.0
}
]
}
]
}
AttendanceListResponse
Returned by GET /list. Reflects applied filters. summary always covers the filtered scope. partiallyAttended only appears when no dayNumber filter is set on a multi-day event.
{
"eventId": "uuid",
"eventTitle": "East African Tech Summit 2026",
"appliedFilters": {
"ticketTypeId": "uuid",
"ticketTypeName": "VIP Pass",
"status": "ALL",
"dayNumber": 1,
"dayName": "Day 1 - Opening",
"buyerType": "ALL",
"search": null
},
"summary": {
"totalTickets": 100,
"present": 90,
"absent": 10,
"partiallyAttended": null,
"attendanceRate": 90.0
},
"attendees": [
{
"ticketInstanceId": "uuid",
"attendeeNumber": "EVT-A3F4B21C-VIP-0042",
"ticketTypeId": "uuid",
"ticketType": "VIP Pass",
"ticketSeries": "VIP-0042",
"attendeeName": "John Doe",
"attendeeEmail": "john@example.com",
"attendeePhone": "+255712345678",
"buyer": {
"buyerName": "Jane Doe",
"buyerEmail": "jane@example.com",
"buyerId": "uuid",
"buyerType": "SYSTEM_USER"
},
"bookingReference": "EVT-A3F4B21C",
"pricePaid": 150.00,
"attendanceStatus": "PRESENT",
"checkInTime": "2026-12-15T09:15:00+03:00",
"checkInLocation": "Main Gate",
"checkedInBy": "Scanner Operator 1",
"scannerId": "uuid-string"
},
{
"ticketInstanceId": "uuid-2",
"attendeeNumber": "EVT-B5D2E12F-GENE-0101",
"ticketType": "General Admission",
"ticketSeries": "GENE-0101",
"attendeeName": "Ali Hassan",
"attendeeEmail": null,
"attendeePhone": null,
"buyer": {
"buyerName": "Ali Hassan",
"buyerEmail": null,
"buyerId": null,
"buyerType": "AT_DOOR"
},
"bookingReference": "EVT-B5D2E12F",
"pricePaid": 50.00,
"attendanceStatus": "ABSENT",
"checkInTime": null,
"checkInLocation": null,
"checkedInBy": null,
"scannerId": null
}
],
"pagination": {
"currentPage": 0,
"pageSize": 20,
"totalPages": 5,
"totalElements": 100,
"hasNext": true,
"hasPrevious": false
}
}
AttendeeDetailResponse
Returned by GET /attendees/{ticketInstanceId}. Full per-day check-in history for one ticket.
{
"ticketInstanceId": "uuid",
"attendeeNumber": "EVT-A3F4B21C-VIP-0042",
"attendeeName": "John Doe",
"attendeeEmail": "john@example.com",
"attendeePhone": "+255712345678",
"ticketType": "VIP Pass",
"ticketSeries": "VIP-0042",
"bookingReference": "EVT-A3F4B21C",
"pricePaid": 150.00,
"overallStatus": "PARTIALLY_ATTENDED",
"daysAttended": 2,
"daysTotal": 3,
"checkInsByDay": [
{
"dayNumber": 1,
"dayName": "Day 1 - Opening",
"dayDate": "2026-12-15",
"status": "CHECKED_IN",
"checkInTime": "2026-12-15T09:15:00+03:00",
"checkInLocation": "Main Gate",
"checkedInBy": "Scanner Operator 1",
"scannerId": "uuid-string"
},
{
"dayNumber": 2,
"dayName": "Day 2 - Conference",
"dayDate": "2026-12-16",
"status": "NOT_CHECKED_IN",
"checkInTime": null,
"checkInLocation": null,
"checkedInBy": null,
"scannerId": null
},
{
"dayNumber": 3,
"dayName": "Day 3 - Closing",
"dayDate": "2026-12-17",
"status": "UPCOMING",
"checkInTime": null,
"checkInLocation": null,
"checkedInBy": null,
"scannerId": null
}
]
}
Endpoints
1. Get Attendance Summary
Endpoint: GET /attendance/{eventId}/summary
Access: 🔒 Event Organizer Only
Path Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| eventId | string (UUID) | Yes | Event identifier |
Success Response: Returns AttendanceSummaryResponse
Success Response Message: "Attendance summary retrieved"
Behavior:
- Validates organizer owns the event
- Returns overall attendance metrics across all tickets
- Breaks down by day (all events, including single-day)
- Breaks down by ticket type with per-day stats
present= checked in for all days,partiallyAttended= some days,absent= noneattendanceRateincludes bothpresentandpartiallyAttendedtickets
Errors:
403 FORBIDDEN: Not event organizer404 NOT_FOUND: Event not found
2. Get Attendance List
Endpoint: GET /attendance/{eventId}/list
Access: 🔒 Event Organizer Only
Path Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| eventId | string (UUID) | Yes | Event identifier |
Query Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| status | enum | No | PRESENT, ABSENT, PARTIALLY_ATTENDED — omit for all |
| dayNumber | integer | No | Filter for a specific day (1, 2, 3...) — omit for overall view |
| ticketTypeId | string (UUID) | No | Filter by ticket type |
| buyerType | enum | No | SYSTEM_USER, AT_DOOR — omit for all |
| search | string | No | Search by attendee name, email, or phone (partial, case-insensitive) |
| page | integer | No | Page number (0-indexed, default: 0) |
| size | integer | No | Items per page (default: 20) |
Success Response: Returns AttendanceListResponse with pagination
Success Response Message: "Attendance list retrieved"
Behavior:
- Returns one row per ticket (not per person)
- One buyer can appear multiple times if they purchased multiple tickets
attendeeNumber=bookingReference + "-" + ticketSeries(unique per ticket)- When
dayNumberis set:attendanceStatusisPRESENTorABSENTfor that specific day - When
dayNumberis omitted:attendanceStatusreflects overall across all days (PARTIALLY_ATTENDEDpossible) summaryblock always reflects the current filter scope (not the full event)partiallyAttendedin summary isnullwhen adayNumberfilter is active
Validation:
dayNumbermust be within valid range for the event (1 to totalDays)ticketTypeIdmust belong to the event
Errors:
403 FORBIDDEN: Not event organizer404 NOT_FOUND: Event not found / invalid day number / ticket type not found
3. Get Attendee Detail
Endpoint: GET /attendance/{eventId}/attendees/{ticketInstanceId}
Access: 🔒 Event Organizer Only
Path Parameters:
| Parameter | Type | Required | Description |
|---|---|---|---|
| eventId | string (UUID) | Yes | Event identifier |
| ticketInstanceId | string (UUID) | Yes | Individual ticket instance identifier |
Success Response: Returns AttendeeDetailResponse
Success Response Message: "Attendee detail retrieved"
Behavior:
- Returns the full check-in history for one specific ticket across all event days
overallStatuscomputed from all dayscheckInsByDaylists every event day with its status and check-in details- Day status reflects whether the day has passed, is today, or is upcoming
Errors:
403 FORBIDDEN: Not event organizer404 NOT_FOUND: Event or ticket not found
Key Concepts
Attendee Number
Every ticket has a unique attendeeNumber formatted as:
{bookingReference}-{ticketSeries}
Example: EVT-A3F4B21C-VIP-0042
Use this as the primary human-readable identifier for a ticket on the attendance list — safer than ticketInstanceId (UUID) for display and manual lookup.
Buyer vs Attendee
These are two different people on the same ticket:
| Field | Who |
|---|---|
attendeeName / attendeeEmail |
The person who will attend (holds the ticket) |
buyer.buyerName / buyer.buyerEmail |
The person who paid |
Example: Jane buys 3 VIP tickets. She is the buyer on all 3. The attendees are John, Ali, and herself.
One buyer can appear multiple times in the list — once per ticket they purchased.
Buyer Types
| Value | Meaning |
|---|---|
SYSTEM_USER |
Bought online — has a platform account, buyerId is populated |
AT_DOOR |
Walk-in sale — only name captured at door, buyerEmail and buyerId are null |
Attendance Status
| Value | Meaning | When |
|---|---|---|
PRESENT |
Checked in | With dayNumber: checked in that day. Without: checked in all days |
ABSENT |
Not checked in | With dayNumber: not that day. Without: never checked in |
PARTIALLY_ATTENDED |
Checked in some days but not all | Only possible without dayNumber filter, on multi-day events |
Day Status (in detail view)
| Value | Meaning |
|---|---|
CHECKED_IN |
Scanned on that day |
NOT_CHECKED_IN |
Day has passed, was not scanned |
UPCOMING |
Day has not happened yet |
Attendance Rate Calculation
attendanceRate = ((present + partiallyAttended) / totalTickets) × 100
Rounded to 2 decimal places.
Per-day rate (in summary byDay):
rate = (checkedIn for that day / totalTickets) × 100
Multi-Day Event Logic
Day Filter Behaviour
dayNumber |
Status scope |
|---|---|
Provided (e.g. ?dayNumber=2) |
Status = did this ticket check in on Day 2? (PRESENT or ABSENT only) |
| Omitted | Status = overall across all days (PRESENT, ABSENT, or PARTIALLY_ATTENDED) |
Day number validation:
Event has 3 days → dayNumber must be 1, 2, or 3
Request dayNumber=5 → 404: "Invalid day 5. Valid: 1-3"
Single-day events: dayNumber is always optional. Omitting it gives the same result as ?dayNumber=1.
Use Cases
Dashboard Overview
GET /attendance/{eventId}/summary
Use: top-of-page stats card
Shows: overall rate, per-day breakdown, per-ticket-type breakdown
Full Attendance Table
GET /attendance/{eventId}/list
Use: default organizer table view — all tickets, all statuses
Who Attended Today (Day 2)
GET /attendance/{eventId}/list?dayNumber=2&status=PRESENT
Shows: tickets checked in on Day 2
Who Missed Today
GET /attendance/{eventId}/list?dayNumber=2&status=ABSENT
Shows: tickets that didn't check in on Day 2 (regardless of other days)
At-Door Walk-Ins Only
GET /attendance/{eventId}/list?buyerType=AT_DOOR
Shows: all tickets sold at the door
Partially Attended (Multi-Day)
GET /attendance/{eventId}/list?status=PARTIALLY_ATTENDED
Shows: tickets that attended some days but not all
Requires: no dayNumber filter
Search by Name
GET /attendance/{eventId}/list?search=john
Matches: attendee name, email, or phone containing "john"
Individual Ticket History
GET /attendance/{eventId}/attendees/{ticketInstanceId}
Shows: full per-day check-in record for one ticket
Quick Reference
HTTP Status Codes
200 OK: Success401 UNAUTHORIZED: Not authenticated403 FORBIDDEN: Not the event organizer404 NOT_FOUND: Event / ticket / day number not found
Attendance Status Values
PRESENT— attended (all days if no day filter)ABSENT— did not attendPARTIALLY_ATTENDED— attended some days (multi-day, no day filter)
Day Status Values
COMPLETED— day has passedONGOING— day is todayUPCOMING— day has not started
Buyer Type Values
SYSTEM_USER— online purchase, has platform accountAT_DOOR— walk-in, name only, no account
Default Pagination
page:0(first page)size:20items per page