Skip to main content

Attendance Analytics API

Author: Josh S. Sakweli, Backend Lead Team Last Updated: 2026-05-23 Version: v2.0

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 both single-day and multi-day events.

Hints:

  • Organizer Only: All endpoints restricted to the event organizer
  • Unified List: Present and absent tickets are in one list — use ?status=PRESENT|ABSENT|PARTIALLY_ATTENDED to filter
  • Ticket-Based Rows: Each row in the list is one ticket, not one person — one buyer can appear multiple times
  • Attendee Number: Unique human-readable ticket ID = 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 = online purchase with account, AT_DOOR = walk-in name only (no account)
  • Day Filtering: ?dayNumber is optional — omit for overall view, provide for per-day status
  • Partial Attendance: PARTIALLY_ATTENDED only applies when no dayNumber filter is set on multi-day events
  • Pagination: Default 20 per page
  • Form Response: formResponseId on each attendee/ticket row links to the buyer's applicant form submission — null if the event had no form or the form was not yet submitted

Standard Response Format

All API responses follow a consistent structure using our Globe Response Builder pattern:

Success Response Structure

{
  "success": true,
  "httpStatus": "OK",
  "message": "Operation completed successfully",
  "action_time": "2026-05-23T10:30:45",
  "data": {
  }
}

Error Response Structure

{
  "success": false,
  "httpStatus": "BAD_REQUEST",
  "message": "Error description",
  "action_time": "2026-05-23T10:30:45",
  "data": "Error description"
}

Standard Response Fields

Field Type Description
success boolean true for successful operations, false for errors
httpStatus string HTTP status name (OK, NOT_FOUND, FORBIDDEN, etc.)
message string Human-readable message describing the result
action_time string ISO 8601 timestamp of when the response was generated
data object Response payload for success, error string for failures

HTTP Method Badge Standards

  • GET - GET - Green (Safe, read-only operations)
  • POST - POST - Blue (Create new resources)
  • PUT - PUT - Yellow (Update/replace entire resource)
  • PATCH - PATCH - Orange (Partial updates)
  • DELETE - DELETE - Red (Remove resources)

Endpoints

1. Get Attendance Summary

Purpose: Returns overall attendance statistics for an event including per-day and per-ticket-type breakdowns. Always covers the full event — no filtering applied.

Endpoint: GET /e-events/attendance/{eventId}/summary

Access Level: 🔒 Protected — Event Organizer Only

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <token>

Path Parameters:

Parameter Type Required Description Validation
eventId UUID Yes Event identifier Must be a valid UUID of an existing event owned by the authenticated organizer

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Attendance summary retrieved",
  "action_time": "2026-05-23T10:30:45",
  "data": {
    "eventId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "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": "3fa85f64-5717-4562-b3fc-2c963f66afa7",
        "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
          }
        ]
      }
    ]
  }
}

Success Response Fields:

Field Description
data.eventId Event UUID
data.eventTitle Event name
data.totalDays Number of event days
data.eventSchedule List of days with dayNumber, dayName, date
data.overallStats.totalTickets Total tickets sold
data.overallStats.present Tickets checked in for all days
data.overallStats.partiallyAttended Tickets checked in for some days (multi-day only)
data.overallStats.absent Tickets never checked in
data.overallStats.attendanceRate ((present + partiallyAttended) / total) × 100, 2 dp
data.overallStats.byDay[].status COMPLETED, ONGOING, or UPCOMING
data.byTicketType Same stats broken down per ticket type

Error Response JSON Sample:

{
  "success": false,
  "httpStatus": "NOT_FOUND",
  "message": "Event not found",
  "action_time": "2026-05-23T10:30:45",
  "data": "Event not found"
}

Standard Error Types:

  • 401 UNAUTHORIZED: Missing or invalid token
  • 403 FORBIDDEN: Authenticated user is not the event organizer
  • 404 NOT_FOUND: Event does not exist

2. Get Attendance List

Purpose: Returns a paginated, filterable list of all tickets for an event. Each row is one ticket. Present and absent tickets are unified in one list — use the status filter to narrow down.

Endpoint: GET /e-events/attendance/{eventId}/list

Access Level: 🔒 Protected — Event Organizer Only

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <token>

Path Parameters:

Parameter Type Required Description Validation
eventId UUID Yes Event identifier Must be a valid UUID of an existing event owned by the authenticated organizer

Query Parameters:

Parameter Type Required Description Validation Default
status enum No Filter by attendance status PRESENT, ABSENT, PARTIALLY_ATTENDED All
dayNumber integer No Filter for a specific event day Must be between 1 and totalDays None (overall)
ticketTypeId UUID No Filter by ticket type Must belong to this event All types
buyerType enum No Filter by how the ticket was purchased SYSTEM_USER, AT_DOOR All
search string No Search by attendee name, email, or phone Partial match, case-insensitive None
page integer No Page number (0-indexed) Min: 0 0
size integer No Items per page Min: 1 20

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Attendance list retrieved",
  "action_time": "2026-05-23T10:30:45",
  "data": {
    "eventId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "eventTitle": "East African Tech Summit 2026",
    "appliedFilters": {
      "ticketTypeId": "3fa85f64-5717-4562-b3fc-2c963f66afa7",
      "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": "3fa85f64-5717-4562-b3fc-2c963f66afa8",
        "formResponseId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
        "attendeeNumber": "EVT-A3F4B21C-VIP-0042",
        "ticketTypeId": "3fa85f64-5717-4562-b3fc-2c963f66afa7",
        "ticketType": "VIP Pass",
        "ticketSeries": "VIP-0042",
        "attendeeName": "John Doe",
        "attendeeEmail": "john@example.com",
        "attendeePhone": "+255712345678",
        "buyer": {
          "buyerName": "Jane Doe",
          "buyerEmail": "jane@example.com",
          "buyerId": "3fa85f64-5717-4562-b3fc-2c963f66afa9",
          "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": "3fa85f64-5717-4562-b3fc-2c963f66afb0"
      },
      {
        "ticketInstanceId": "3fa85f64-5717-4562-b3fc-2c963f66afb1",
        "formResponseId": null,
        "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
    }
  }
}

Success Response Fields:

Field Description
data.appliedFilters Echo of all active filters so the client knows what was applied
data.summary.totalTickets Total tickets matching the ticket type filter (unaffected by status/search)
data.summary.present Tickets with PRESENT status under current filters
data.summary.absent Tickets with ABSENT status under current filters
data.summary.partiallyAttended null when dayNumber is active; count when viewing overall multi-day
data.summary.attendanceRate ((present + partiallyAttended) / total) × 100, 2 dp
data.attendees[].ticketInstanceId Unique ticket instance UUID
data.attendees[].formResponseId UUID of the buyer's applicant form response — null if the event had no form
data.attendees[].attendeeNumber Unique readable ID = bookingReference + "-" + ticketSeries
data.attendees[].attendanceStatus PRESENT, ABSENT, or PARTIALLY_ATTENDED
data.attendees[].buyer.buyerType SYSTEM_USER (online) or AT_DOOR (walk-in)
data.attendees[].buyer.buyerId Populated for SYSTEM_USER, null for AT_DOOR
data.attendees[].checkInTime null when attendanceStatus is ABSENT
data.pagination Standard pagination envelope

Notes:

  • When dayNumber is provided: attendanceStatus is PRESENT or ABSENT for that specific day only
  • When dayNumber is omitted: attendanceStatus reflects the overall across all days (PARTIALLY_ATTENDED possible)
  • summary reflects the current filter scope, not the whole event
  • partiallyAttended in summary is null when a dayNumber filter is active

Error Response JSON Sample:

{
  "success": false,
  "httpStatus": "NOT_FOUND",
  "message": "Invalid day 5. Valid: 1-3",
  "action_time": "2026-05-23T10:30:45",
  "data": "Invalid day 5. Valid: 1-3"
}

Standard Error Types:

  • 401 UNAUTHORIZED: Missing or invalid token
  • 403 FORBIDDEN: Authenticated user is not the event organizer
  • 404 NOT_FOUND: Event not found / day number out of range / ticket type not found

3. Get Attendee Detail

Purpose: Returns the full check-in history for a single ticket across all event days. Shows per-day status including upcoming days.

Endpoint: GET /e-events/attendance/{eventId}/attendees/{ticketInstanceId}

Access Level: 🔒 Protected — Event Organizer Only

Authentication: Bearer Token

Request Headers:

Header Type Required Description
Authorization string Yes Bearer <token>

Path Parameters:

Parameter Type Required Description Validation
eventId UUID Yes Event identifier Must be owned by the authenticated organizer
ticketInstanceId UUID Yes Individual ticket instance identifier Must belong to a booking under this event

Success Response JSON Sample:

{
  "success": true,
  "httpStatus": "OK",
  "message": "Attendee detail retrieved",
  "action_time": "2026-05-23T10:30:45",
  "data": {
    "ticketInstanceId": "3fa85f64-5717-4562-b3fc-2c963f66afa8",
    "formResponseId": "3fa85f64-5717-4562-b3fc-2c963f66afa6",
    "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": "3fa85f64-5717-4562-b3fc-2c963f66afb0"
      },
      {
        "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
      }
    ]
  }
}

Success Response Fields:

Field Description
data.ticketInstanceId Unique ticket instance UUID
data.formResponseId UUID of the buyer's applicant form response — null if the event had no form
data.attendeeNumber Unique readable ID = bookingReference + "-" + ticketSeries
data.overallStatus PRESENT (all days), PARTIALLY_ATTENDED (some), ABSENT (none)
data.daysAttended Count of days this ticket was checked in
data.daysTotal Total number of event days
data.checkInsByDay[].status CHECKED_IN, NOT_CHECKED_IN, or UPCOMING
data.checkInsByDay[].checkInTime null when not checked in or day is upcoming
data.checkInsByDay[].checkedInBy Name of the scanner operator who processed the check-in

Error Response JSON Sample:

{
  "success": false,
  "httpStatus": "NOT_FOUND",
  "message": "Ticket not found",
  "action_time": "2026-05-23T10:30:45",
  "data": "Ticket not found"
}

Standard Error Types:

  • 401 UNAUTHORIZED: Missing or invalid token
  • 403 FORBIDDEN: Authenticated user is not the event organizer
  • 404 NOT_FOUND: Event not found or ticket instance does not belong to this event

Quick Reference Guide

Attendance Status Values

Value Meaning Available when
PRESENT Checked in (all days if no day filter) Always
ABSENT Never checked in Always
PARTIALLY_ATTENDED Checked in some days but not all No dayNumber filter, multi-day events only

Day Status Values

Value Meaning
CHECKED_IN Ticket was scanned on that day
NOT_CHECKED_IN Day passed, ticket not scanned
UPCOMING Day has not started yet

Buyer Type Values

Value buyerEmail buyerId Meaning
SYSTEM_USER Populated Populated Bought online, has platform account
AT_DOOR null null Walk-in sale, name only captured at door

Common HTTP Status Codes

  • 200 OK: Successful request
  • 401 UNAUTHORIZED: Authentication required or token invalid
  • 403 FORBIDDEN: Not the event organizer
  • 404 NOT_FOUND: Event, ticket, or day number not found
  • 500 INTERNAL_SERVER_ERROR: Unexpected server error