Groups

Analytics dashboard data for a group

Changed on

Return every figure the analytics dashboard renders, in one read-only response: submission totals, above-threshold counts, medians, membership, a time series, a score distribution, paginated breakdowns by course and by assignment, and a paginated list of the submissions themselves.

Access. Group owners only. A teacher or student of the same group receives 403, as does a member of any other group.

What counts as a submission. A text belonging to the group, not deleted, whose created_at (the moment it was submitted, not the moment its check finished) falls inside [date_from, date_to] in the response timezone, and which matches the course / course_id and assignment / assignment_id filters.

Scores. Plagiarism comes from the text's single plagiarism report. AI comes from the most recent completed AI check on that text, so a later failed recheck does not erase an earlier score and a later successful one replaces it. A submission missing either score still counts in data.submissions.total but is excluded from every calculation based on that score: the above-threshold counts, the median, the average, the distribution, and the table flag columns.

Thresholds. ai_threshold and plagiarism_threshold are independent and inclusive (>=). They never affect data.submissions.total, data.members, or filters.options.

Courses and assignments. A course or assignment name exists only for submissions that arrived through an LMS integration, and only where that integration recorded the name in the shared name tables. Submissions without a resolvable course name are counted everywhere else but do not appear in data.courses, data.assignments, or filters.options, so the rows of those tables can sum to less than data.submissions.total. Names are merged across integrations and terms, so one course name is one row however many LMS courses carry it. course_id and assignment_id identify those names (one id per distinct name), not an LMS course or assignment.

Submissions list. data.submissions.items lists the filtered submissions one per row, with the submitting user, both scores and the course and assignment. The date range and the course / assignment filters apply to it like to everything else; the submissions_* parameters then narrow, sort and page the list only - no total, chart or table changes when they do. So data.submissions.pagination.total_count can be lower than data.submissions.total.

Pagination. Three independent paginators - courses, assignments, submissions - each with its own <table>_page / <table>_per_page parameters and its own pagination object inside the table. Read pagination.page_count to know where to stop; a page past the end is empty, not an error.

Timezone. Always UTC. Range boundaries and time-series buckets are drawn in it, and it is echoed in filters.timezone.

Caching. A successful response is cached server-side for ten minutes, keyed by the group and every parameter below, and cannot be bypassed from the request. Figures can therefore trail reality by up to ten minutes, which is most visible during a submission deadline. Changing any parameter — a page number or a sort direction included — is a fresh read rather than a cached one.

get/api/v1/groups/statistics/dashboard/{id}/

Request

  • Base URL
    https://plagiarismcheck.org
  • Auth
    API key in header X-API-TOKEN

Path parameters

idinteger required

Numeric group ID.

Query parameters

date_fromstring date

First day of the range, inclusive, in the response timezone. Must be earlier than or equal to date_to; there is no limit on how wide the range is. Defaults to the day the group was created, so a request without dates covers the group's whole history - or to date_to, if that is earlier.

date_tostring date

Last day of the range, inclusive, in the response timezone. Defaults to today.

coursestring nullable

Restrict every figure except membership to one course, matched exactly on the course name after trimming surrounding whitespace. Omitted, empty, or whitespace-only means all courses.

assignmentstring nullable

Restrict every figure except membership to one assignment, matched exactly on the assignment name after trimming surrounding whitespace. Without course it matches that assignment name in every course, which is intended: two courses can both run an assignment called "Essay 2". Omitted, empty, or whitespace-only means all assignments.

course_idinteger nullable

Restrict every figure except membership to one course, by the course_id that filters.options.courses and the table rows publish. The id names one distinct course name, so this matches exactly what course with that name would. Sending both course and course_id is a 422 against course_id. Omitted or empty means all courses.

assignment_idinteger nullable

Restrict every figure except membership to one assignment, by the assignment_id that filters.options.assignments and the assignments table publish. Like assignment, without a course filter it matches that assignment name in every course. Sending both assignment and assignment_id is a 422 against assignment_id. Omitted or empty means all assignments.

step'day' | 'week' | 'month'

Time-series bucket size. Weeks are ISO weeks and start on Monday; months are calendar months. There is no limit on the number of buckets: a range of several years at step=day returns one per day.

ai_thresholdnumber float

Minimum AI score, inclusive, for a submission to be counted by any AI figure. Does not affect data.submissions.total, data.members, or filters.options.

plagiarism_thresholdnumber float

Minimum plagiarism score, inclusive, for a submission to be counted by any plagiarism figure. Independent of ai_threshold.

courses_sort'course_name' | 'submissions' | 'ai_flag' | 'plagiarism_flag'

Column to sort data.courses.items by. ai_flag and plagiarism_flag sort by the percentage, not by the raw count. Ties break on course_name ascending.

courses_dir'asc' | 'desc'

Sort direction for data.courses.items.

courses_pageinteger

One-based page number for data.courses.items. A page past the end returns no items.

courses_per_pageinteger

Number of rows per page for data.courses.items.

assignments_sort'assignment_name' | 'course_name' | 'submissions' | 'ai_flag' | 'plagiarism_flag'

Column to sort data.assignments.items by. Ties break on assignment_name ascending, then course_name ascending.

assignments_dir'asc' | 'desc'

Sort direction for data.assignments.items.

assignments_pageinteger

One-based page number for data.assignments.items.

assignments_per_pageinteger

Number of rows per page for data.assignments.items.

submissions_sort'submitted_at' | 'user_name' | 'user_email' | 'plagiarism_percent' | 'ai_percent' | 'course_name' | 'assignment_name'

Column to sort data.submissions.items by. user_name sorts a user with no name by their email, which is what the row shows in its place. A missing score, course or assignment sorts last in both directions. Ties break on the newest submission first.

submissions_dir'asc' | 'desc'

Sort direction for data.submissions.items.

submissions_pageinteger

One-based page number for data.submissions.items. A page past the end returns no items.

submissions_per_pageinteger

Number of rows per page for data.submissions.items.

submissions_coursestring nullable

List only: keep submissions whose course name contains this text, case-insensitively. % and _ are matched literally. Trimmed; empty means off. A submission with no course never matches. Unlike course, this narrows data.submissions.items and nothing else.

submissions_assignmentstring nullable

List only: keep submissions whose assignment name contains this text, case-insensitively. Same rules as submissions_course.

submissions_userstring nullable

List only: keep submissions whose submitting user's name or email contains this text, case-insensitively. Same rules as submissions_course.

submissions_user_idinteger nullable

List only - keep one user's submissions, by user_id. Empty means off.

submissions_flagged'ai' | 'plagiarism' | 'any' nullable

List only: keep the submissions at or above a threshold - ai (AI score >= ai_threshold), plagiarism (plagiarism score >= plagiarism_threshold) or any (either). A submission without the relevant score is never flagged. Omitted or empty lists every submission, unscored ones included.

Response

The request succeeded and returned the dashboard figures.

successboolean required

Example response

{
  "success": true,
  "filters": {
    "group_id": 12,
    "date_from": "2026-06-21",
    "date_to": "2026-09-18",
    "timezone": "UTC",
    "course": "ENG 210 - Composition",
    "assignment": "Essay 2 - Argument",
    "course_id": 4,
    "assignment_id": 17,
    "step": "week",
    "ai_threshold": 20,
    "plagiarism_threshold": 15,
    "sort": {
      "courses": {
        "field": "submissions",
        "direction": "desc"
      },
      "assignments": {
        "field": "submissions",
        "direction": "desc"
      },
      "submissions": {
        "field": "submissions",
        "direction": "desc"
      }
    },
    "pagination": {
      "courses": {
        "page": 1,
        "per_page": 20
      },
      "assignments": {
        "page": 1,
        "per_page": 20
      },
      "submissions": {
        "page": 1,
        "per_page": 20
      }
    },
    "submissions": {
      "course": "compos",
      "user": "smith",
      "flagged": "any"
    },
    "options": {
      "courses": [
        {
          "course_id": 4,
          "course_name": "ENG 210 - Composition"
        }
      ],
      "assignments": [
        {
          "assignment_id": 17,
          "assignment_name": "Essay 2 - Argument",
          "course_id": 4,
          "course_name": "ENG 210 - Composition"
        }
      ]
    }
  },
  "data": {
    "submissions": {
      "total": 4828,
      "ai_scored": 4610,
      "plagiarism_scored": 4828,
      "items": [
        {
          "user_id": 5021,
          "user_name": "Ann Smith",
          "user_email": "ann.smith@north.edu",
          "text_id": 90211,
          "plagiarism_percent": 12.25,
          "ai_percent": 81.5,
          "course_id": 4,
          "course_name": "ENG 210 - Composition",
          "assignment_id": 17,
          "assignment_name": "Essay 2 - Argument",
          "submitted_at": 1789029000
        }
      ],
      "pagination": {
        "last": 3,
        "current": 1,
        "num_items_per_page": 30,
        "first": 1,
        "page_count": 3,
        "total_count": 67,
        "page_range": 3,
        "start_page": 1,
        "end_page": 3,
        "pages_in_range": [
          1,
          2,
          3
        ],
        "first_page_in_range": 1,
        "lastPage_in_range": 3,
        "current_item_count": 30,
        "first_item_number": 1,
        "last_item_number": 30
      }
    },
    "ai_above_threshold": {
      "count": 912,
      "percent": 19.78
    },
    "plagiarism_above_threshold": {
      "count": 912,
      "percent": 19.78
    },
    "median": {
      "ai": 4.2,
      "plagiarism": 6.8
    },
    "members": {
      "total": 540,
      "teachers": 32,
      "students": 508
    },
    "timeseries": [
      {
        "period_start": "2026-06-22",
        "period_end": "2026-06-28",
        "submissions": 96,
        "ai_avg": 38.12,
        "ai_flagged": 74,
        "ai_scored": 91,
        "ai_percent": 81.32,
        "plagiarism_avg": 24.4,
        "plagiarism_flagged": 31,
        "plagiarism_scored": 96,
        "plagiarism_percent": 32.29
      }
    ],
    "distribution": [
      {
        "from": 90,
        "to": 100,
        "ai": 41,
        "plagiarism": 7
      }
    ],
    "courses": {
      "items": [
        {
          "course_id": 4,
          "course_name": "ENG 210 - Composition",
          "submissions": 1204,
          "ai_flag": 24.09,
          "ai_flag_count": 290,
          "ai_scored": 1204,
          "plagiarism_flag": 7.97,
          "plagiarism_flag_count": 96,
          "plagiarism_scored": 1204
        }
      ],
      "pagination": {
        "last": 3,
        "current": 1,
        "num_items_per_page": 30,
        "first": 1,
        "page_count": 3,
        "total_count": 67,
        "page_range": 3,
        "start_page": 1,
        "end_page": 3,
        "pages_in_range": [
          1,
          2,
          3
        ],
        "first_page_in_range": 1,
        "lastPage_in_range": 3,
        "current_item_count": 30,
        "first_item_number": 1,
        "last_item_number": 30
      }
    },
    "assignments": {
      "items": [
        {
          "assignment_id": 17,
          "assignment_name": "Essay 2 - Argument",
          "course_id": 4,
          "course_name": "ENG 210 - Composition",
          "submissions": 1204,
          "ai_flag": 24.09,
          "ai_flag_count": 290,
          "ai_scored": 1204,
          "plagiarism_flag": 7.97,
          "plagiarism_flag_count": 96,
          "plagiarism_scored": 1204
        }
      ],
      "pagination": {
        "last": 3,
        "current": 1,
        "num_items_per_page": 30,
        "first": 1,
        "page_count": 3,
        "total_count": 67,
        "page_range": 3,
        "start_page": 1,
        "end_page": 3,
        "pages_in_range": [
          1,
          2,
          3
        ],
        "first_page_in_range": 1,
        "lastPage_in_range": 3,
        "current_item_count": 30,
        "first_item_number": 1,
        "last_item_number": 30
      }
    }
  }
}

Changes

    • breaking

      the /// response's property type changed from string to object for status

    • info

      added the new optional query request parameter assignment_id

    • info

      added the new optional query request parameter course_id

    • info

      added the new optional query request parameter submissions_assignment

    • info

      added the new optional query request parameter submissions_course

    • info

      added the new optional query request parameter submissions_dir

    • info

      added the new optional query request parameter submissions_flagged

    • info

      added the new optional query request parameter submissions_page

    • info

      added the new optional query request parameter submissions_per_page

    • info

      added the new optional query request parameter submissions_sort

    • info

      added the new optional query request parameter submissions_user

    • info

      added the new optional query request parameter submissions_user_id

    • info

      added the required property //////// to the response with the status

    • info

      added the required property ///// to the response with the status

    • info

      added the required property //// to the response with the status

    • info

      added the required property // to the response with the status

    • info

      added the required property // to the response with the status

    • info

      added the required property / to the response with the status

    • info

      added the required property / to the response with the status

    • info

      added the required property //// to the response with the status

    • info

      added the required property //// to the response with the status

    • info

      added the required property //// to the response with the status

    • info

      added the required property //// to the response with the status

    • info

      added the required property // to the response with the status

    • info

      added the required property // to the response with the status

    • info

      added the required property / to the response with the status

    • info

      endpoint added