Session Time Adjustments

Store one time adjustment per session, then read it back by session.

Preview: a session's adjusted time is computed by a port of the StudyFilm feed's daily arithmetic. Values may change until a production parity check against the feed is accepted. Until then the feed's daily reports stay the reference for schools.

Note: This guide covers the integration flow. See the API Reference for complete endpoint documentation, all parameters, and response schemas.

What a time adjustment is

A session's base time is split into seven classes. Wasted time and confirmed academic-integrity time are deducted. What remains is the adjusted time:

  • adjustedSeconds = baseSeconds - deductedSeconds.
  • secondsByClass holds the seven classes, and their values sum to baseSeconds.
  • suspectedSeconds counts time under suspected, unconfirmed integrity spans. It is reported, never deducted.

Values are whole seconds. Divide by 60 for minutes.

The platform keeps one record per session. A later write for the same session replaces it.

Prerequisites

  1. Register your App and obtain OAuth credentials. See Level 0: Register Your App and Authentication.

  2. Request the Caliper event scopes for your M2M client:

    • Write: https://purl.imsglobal.org/spec/caliper/v1p2/scope/events.write
    • Read: https://purl.imsglobal.org/spec/caliper/v1p2/scope/events.readonly
  3. Own the session's organization. A caller without organization access receives 403.

Classes

Class Deducted
PRODUCTIVE No
LOW_PRODUCTIVITY No
SCHOOL No
SYSTEM_FAILURE No
WASTED Yes
INSINCERE Yes
UNOBSERVED No

INSINCERE is time covered by a confirmed academic-integrity violation. UNOBSERVED is time where nothing could be observed. The other classes are the StudyFilm window labels.

The producer decides which classes it deducts under its ruleVersion. deductedSeconds is the producer's total.

Integrity status

Value Meaning
CONFIRMED At least one confirmed academic-integrity violation.
SUSPECT Suspected, unconfirmed violations only.
CLEAN Reviewed and clean.
NOT_ESCALATED Screening found nothing to review.
UNJUDGED Review did not finish. Nothing is deducted for integrity.

Fields

Field Meaning
baseSeconds Session duration the producer classified.
adjustedSeconds baseSeconds minus deductedSeconds.
deductedSeconds Seconds removed from the base.
suspectedSeconds Seconds under suspected integrity spans. Never deducted.
secondsByClass All seven classes, each a non-negative integer, summing to baseSeconds.
integrityStatus One of the values above.
ruleVersion Version of the rules that produced the record, 1 to 64 characters.
source Producer id, 1 to 64 characters.
computedAt Instant the producer computed the record, RFC 3339.
id, dateCreated, dateLastModified Server-assigned.

Step 1: Store a time adjustment

POST /session/1.0/sessions/{sessionId}/time-adjustment

Requires events.write. sessionId is the Caliper session id. A later write for the same session replaces the record.

Request body:

{
  "baseSeconds": 1200,
  "adjustedSeconds": 960,
  "deductedSeconds": 240,
  "suspectedSeconds": 0,
  "secondsByClass": {
    "PRODUCTIVE": 840,
    "LOW_PRODUCTIVITY": 0,
    "SCHOOL": 120,
    "SYSTEM_FAILURE": 0,
    "WASTED": 240,
    "INSINCERE": 0,
    "UNOBSERVED": 0
  },
  "integrityStatus": "NOT_ESCALATED",
  "ruleVersion": "feed-f215c05",
  "source": "window-graph",
  "computedAt": "2026-03-10T09:35:00.000Z"
}

Response 200:

{
  "sessionId": "00000000-0000-4000-8000-000000000001",
  "timeAdjustment": {
    "id": "11111111-1111-4111-8111-111111111111",
    "baseSeconds": 1200,
    "adjustedSeconds": 960,
    "deductedSeconds": 240,
    "suspectedSeconds": 0,
    "secondsByClass": {
      "PRODUCTIVE": 840,
      "LOW_PRODUCTIVITY": 0,
      "SCHOOL": 120,
      "SYSTEM_FAILURE": 0,
      "WASTED": 240,
      "INSINCERE": 0,
      "UNOBSERVED": 0
    },
    "integrityStatus": "NOT_ESCALATED",
    "ruleVersion": "feed-f215c05",
    "source": "window-graph",
    "computedAt": "2026-03-10T09:35:00.000Z",
    "dateCreated": "2026-03-10T09:35:01.000Z",
    "dateLastModified": "2026-03-10T09:35:01.000Z"
  }
}

Step 2: Read one session

GET /session/1.0/sessions/{sessionId}/time-adjustment

Requires events.readonly. A stored record returns the same shape as the write response.

A known session with no record yet returns 200 with timeAdjustment: null:

{
  "sessionId": "00000000-0000-4000-8000-000000000001",
  "timeAdjustment": null
}

That means no adjustment has been computed yet. Use the session's raw duration until one arrives. An unknown or revoked session returns 404.

Errors

Status Cause
400 secondsByClass does not sum to baseSeconds, is missing a class, or has an extra one. adjustedSeconds is not baseSeconds minus deductedSeconds. A value is negative or not an integer.
401 The token is missing, expired, or lacks the scope the endpoint needs.
403 The caller lacks organization access, or a student tries to write a record.
404 The session is unknown or revoked.