Skip to main content

Rostering API

The Rostering API provides OneRoster v1.2-compatible endpoints for managing the full roster hierarchy: users, courses, classes, enrollments, organizations, and terms. All endpoints require Authorization: Bearer <token>. See the Curriculum API for units, lessons, and resources that build on courses created here.

Base prefix: https://api.alpha-1edtech.ai/rostering/1.0


GET /rostering/1.0/users​

Returns a paginated list of users (students and staff). Supports filtering, sorting, and field selection.

Filter examples:

  • filter=email='alice@school.edu' — find a user by exact email
  • filter=status='active' — only active users
  • filter=familyName~'Smi' — last name contains "Smi"
  • filter=status='active' AND role='student' — active students only

Scope: roster.readonly

Query params​

NameDescriptionRequired
limitMaximum records per page (default 100, max 1000)no
offsetNumber of records to skip (default 0)no
filterOneRoster filter expression. Operators: =, !=, >, >=, <, <=, ~ (contains), @ (regex). Combine with AND / OR.no
sortField to sort byno
orderBySort direction: asc or descno
searchFree-text search termno
fieldsComma-separated list of fields to includeno

Response​

200 OK — { "users": [...], "offset": 0, "limit": 100, "total": N }

Each user object includes: sourcedId, givenName, familyName, email, enabledUser, roles, grades, primaryOrg.

Example​

curl "https://api.alpha-1edtech.ai/rostering/1.0/users?filter=status%3D'active'&limit=10" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

GET /rostering/1.0/users/:sourcedId​

Returns a single user by their sourcedId.

Scope: roster.readonly

Path params​

NameDescription
sourcedIdUser UUID

Response​

200 OK — User object. 404 if not found.

Example​

curl "https://api.alpha-1edtech.ai/rostering/1.0/users/11111111-1111-1111-1111-111111111111" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

PUT /rostering/1.0/users/:sourcedId​

Create or update a user using a standard OneRoster v1.2 User payload. If the user exists, it is updated; otherwise a new user is created.

The sourcedId in the URL path must match the sourcedId in the request body. You generate the UUID.

Required fields: sourcedId, status, dateLastModified, enabledUser, givenName, familyName, email, roles (at least one with org reference).

Get your org sourcedId from GET /rostering/1.0/orgs.

Scope: roster.createput

Path params​

NameDescription
sourcedIdUser UUID (must match body)

Request body​

Wrapped as { "user": { ... } }.

FieldTypeRequiredDescription
sourcedIdstring (UUID)yesMust match the URL path parameter
dateLastModifiedstring (ISO 8601)yesTimestamp of this update
givenNamestringyesFirst name
familyNamestringyesLast name
emailstringyesEmail address — used as identifier when sending events
enabledUserstringno"true" or "false" (defaults to "true")
rolesarraynoRole assignments; each entry has role, org.sourcedId
gradesstring[]noGrade levels (e.g., ["5"])
primaryOrg{ sourcedId }noPrimary school/org reference
usernamestringnoLogin username
metadataobjectnoFree-form metadata blob

Response​

201 Created or 200 OK — { "status": "...", "sourcedId": "..." }

403 Forbidden — User not owned by your client application.

Example​

curl -X PUT "https://api.alpha-1edtech.ai/rostering/1.0/users/22222222-2222-2222-2222-222222222222" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"user": {
"sourcedId": "22222222-2222-2222-2222-222222222222",
"dateLastModified": "2026-01-15T00:00:00.000Z",
"givenName": "Alice",
"familyName": "Smith",
"email": "alice@school.edu",
"roles": [{ "role": "student", "org": { "sourcedId": "ORG_SOURCED_ID" } }]
}
}'

DELETE /rostering/1.0/users/:sourcedId​

Soft-deletes a user. Returns HTTP 204 with an empty body on success.

Ownership: partners may only delete users they created (i.e. metadata.createdByApp matches the caller) or sandbox-scoped users (primary org partner-sandbox). Cross-tenant DELETE is rejected with HTTP 403. Alpha-owned / Alpha-synced students are not partner-deletable.

Scope: roster.createput

Path params​

NameDescription
sourcedIdUser UUID

Response​

204 No Content on success. 403 Forbidden — ownership violation. 404 — not found.

Example​

curl -X DELETE "https://api.alpha-1edtech.ai/rostering/1.0/users/22222222-2222-2222-2222-222222222222" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

GET /rostering/1.0/users/:sourcedId/enrollments​

Returns all enrollments for a user.

Scope: roster.readonly

Path params​

NameDescription
sourcedIdUser UUID

Query params​

Standard pagination query params (limit, offset, filter, sort, orderBy, search, fields).

Response​

200 OK — { "enrollments": [...], "offset": 0, "limit": 100, "total": N }

Each enrollment includes: sourcedId, role, user, class, course, school, beginDate, endDate.

Example​

curl "https://api.alpha-1edtech.ai/rostering/1.0/users/22222222-2222-2222-2222-222222222222/enrollments" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

GET /rostering/1.0/users/:sourcedId/agents​

Returns all agents (parents, guardians) linked to a student.

Scope: roster.readonly

Path params​

NameDescription
sourcedIdStudent UUID

Response​

200 OK — { "agents": [...] } — array of user objects.

Example​

curl "https://api.alpha-1edtech.ai/rostering/1.0/users/22222222-2222-2222-2222-222222222222/agents" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

GET /rostering/1.0/users/:sourcedId/linked-users​

Returns all agents and students linked to this user.

Scope: roster.readonly

Path params​

NameDescription
sourcedIdUser UUID

Response​

200 OK — { "agents": [...], "students": [...] } — arrays of user objects.

Example​

curl "https://api.alpha-1edtech.ai/rostering/1.0/users/22222222-2222-2222-2222-222222222222/linked-users" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

PUT /rostering/1.0/students/:sourcedId/agents/:agentId​

Link a parent/guardian user to a student.

Scope: roster.createput

Path params​

NameDescription
sourcedIdStudent UUID
agentIdAgent (parent/guardian) UUID

Response​

200 OK — { "status": "ok" }

Example​

curl -X PUT "https://api.alpha-1edtech.ai/rostering/1.0/students/22222222-2222-2222-2222-222222222222/agents/33333333-3333-3333-3333-333333333333" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

DELETE /rostering/1.0/students/:sourcedId/agents/:agentId​

Unlink a parent/guardian user from a student.

Scope: roster.createput

Path params​

NameDescription
sourcedIdStudent UUID
agentIdAgent (parent/guardian) UUID

Response​

200 OK — { "status": "ok" }

Example​

curl -X DELETE "https://api.alpha-1edtech.ai/rostering/1.0/students/22222222-2222-2222-2222-222222222222/agents/33333333-3333-3333-3333-333333333333" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

GET /rostering/1.0/courses​

Returns a paginated list of courses.

Filter examples:

  • filter=status='active' — only active courses
  • filter=subjects~'Math' — courses covering Math

Scope: roster.readonly

Query params​

Standard pagination query params (limit, offset, filter, sort, orderBy, search, fields).

Response​

200 OK — { "courses": [...], "offset": 0, "limit": 100, "total": N }

Each course includes: sourcedId, title, courseCode, subjects, grades, org, courseType, and extensions. Spaced-repetition review courses use courseType: "spaced-repetition" and are supplemental retention review courses, not normal progression courses.

Example​

curl "https://api.alpha-1edtech.ai/rostering/1.0/courses?filter=subjects~'Math'" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

GET /rostering/1.0/courses/:sourcedId​

Returns a single course by its sourcedId.

Scope: roster.readonly

Path params​

NameDescription
sourcedIdCourse UUID

Response​

200 OK — Course object. 404 if not found.

Example​

curl "https://api.alpha-1edtech.ai/rostering/1.0/courses/44444444-4444-4444-4444-444444444444" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

PUT /rostering/1.0/courses/:sourcedId​

Create or update a course using a standard OneRoster v1.2 Course payload.

Required fields: sourcedId, status, dateLastModified, title, courseCode, org.

The course is automatically linked to your application for event processing. The subjects array determines which Caliper events (by extensions.subject) are attributed to this course.

Scope: roster.createput

Path params​

NameDescription
sourcedIdCourse UUID (must match body)

Request body​

Wrapped as { "course": { ... } }.

FieldTypeRequiredDescription
sourcedIdstring (UUID)yesMust match the URL path parameter
dateLastModifiedstring (ISO 8601)yesTimestamp of this update
titlestringyesDisplay name (e.g., "Math Grade 5")
courseCodestringnoShort code (e.g., "MATH-G5")
org{ sourcedId }yesOrganization owning this course
subjectsstring[]noSubjects (e.g., ["Math"]) — used for event attribution
gradesstring[]noGrade levels (e.g., ["5"])
metadataobjectnoAdditional metadata

Response​

201 Created or 200 OK — { "status": "...", "sourcedId": "..." }

Example​

curl -X PUT "https://api.alpha-1edtech.ai/rostering/1.0/courses/44444444-4444-4444-4444-444444444444" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"course": {
"sourcedId": "44444444-4444-4444-4444-444444444444",
"dateLastModified": "2026-01-15T00:00:00.000Z",
"title": "Math Grade 5",
"courseCode": "MATH-G5",
"org": { "sourcedId": "ORG_SOURCED_ID" },
"subjects": ["Math"],
"grades": ["5"]
}
}'

DELETE /rostering/1.0/courses/:sourcedId​

Soft-deletes a Course. Returns HTTP 204 with an empty body on success.

Cascade protection: if any Enrollment under this Course is currently active, the DELETE is rejected with HTTP 409 Conflict and { "error": "Cannot delete course with active enrollments" }. Withdraw active enrollments first, then retry.

Scope: roster.createput

Path params​

NameDescription
sourcedIdCourse UUID

Response​

204 No Content on success. 403 — ownership violation. 404 — not found. 409 — active enrollments exist.

Example​

curl -X DELETE "https://api.alpha-1edtech.ai/rostering/1.0/courses/44444444-4444-4444-4444-444444444444" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

GET /rostering/1.0/classes​

Returns a paginated list of classes (sections of courses).

Filter examples:

  • filter=course.sourcedId='COURSE_UUID' — classes for a specific course
  • filter=status='active' — only active classes

Scope: roster.readonly

Query params​

Standard pagination query params (limit, offset, filter, sort, orderBy, search, fields).

Response​

200 OK — { "classes": [...], "offset": 0, "limit": 100, "total": N }

Example​

curl "https://api.alpha-1edtech.ai/rostering/1.0/classes?filter=course.sourcedId%3D'44444444-4444-4444-4444-444444444444'" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

GET /rostering/1.0/classes/:sourcedId​

Returns a single class by its sourcedId.

Scope: roster.readonly

Path params​

NameDescription
sourcedIdClass UUID

Response​

200 OK — { "class": { ... } }. 404 if not found.

Example​

curl "https://api.alpha-1edtech.ai/rostering/1.0/classes/55555555-5555-5555-5555-555555555555" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

PUT /rostering/1.0/classes/:sourcedId​

Create or update a class (section) using a standard OneRoster v1.2 Class payload. In OneRoster, students enroll in classes, which are instances of courses.

Required fields: sourcedId, status, dateLastModified, title, course (reference), org, classType, terms (can be empty []).

Typical flow: Create a course first, then create a class for that course, then enroll students in the class.

Scope: roster.createput

Path params​

NameDescription
sourcedIdClass UUID (must match body)

Request body​

Wrapped as { "class": { ... } }.

FieldTypeRequiredDescription
sourcedIdstring (UUID)yesMust match the URL path parameter
dateLastModifiedstring (ISO 8601)yesTimestamp
titlestringyesDisplay title (e.g., "Math Grade 5 - Section 1")
course{ sourcedId }yesParent course reference
org{ sourcedId }yesSchool/org reference
classType"scheduled" or "homeroom"yesClass type
termsarray of { sourcedId }noAcademic session references (can be [])
classCodestringnoShort human-readable code
metadataobjectnoAdditional metadata

Response​

201 Created or 200 OK — { "status": "...", "sourcedId": "..." }

Example​

curl -X PUT "https://api.alpha-1edtech.ai/rostering/1.0/classes/55555555-5555-5555-5555-555555555555" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"class": {
"sourcedId": "55555555-5555-5555-5555-555555555555",
"dateLastModified": "2026-01-15T00:00:00.000Z",
"title": "Math Grade 5 - Section 1",
"course": { "sourcedId": "44444444-4444-4444-4444-444444444444" },
"org": { "sourcedId": "ORG_SOURCED_ID" },
"classType": "scheduled",
"terms": []
}
}'

DELETE /rostering/1.0/classes/:sourcedId​

Soft-deletes a Class. Returns HTTP 204.

Ownership: enforced via the Class's parent Course. If the parent Course is not owned by your client, the DELETE is rejected with HTTP 403.

Scope: roster.createput

Path params​

NameDescription
sourcedIdClass UUID

Response​

204 No Content on success. 403 — ownership violation. 404 — not found.

Example​

curl -X DELETE "https://api.alpha-1edtech.ai/rostering/1.0/classes/55555555-5555-5555-5555-555555555555" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

GET /rostering/1.0/classes/:sourcedId/enrollments​

Returns all enrollments in a class. Mirrors GET /users/{id}/enrollments but scoped to a class section.

Filter examples (AND-ed onto the implicit class scope):

  • filter=role='student' — only student enrollments
  • filter=status='active' — only active enrollments

Scope: roster.readonly

Path params​

NameDescription
sourcedIdClass UUID

Query params​

Standard pagination query params.

Response​

200 OK — { "enrollments": [...], "offset": 0, "limit": 100, "total": N }

Example​

curl "https://api.alpha-1edtech.ai/rostering/1.0/classes/55555555-5555-5555-5555-555555555555/enrollments" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

GET /rostering/1.0/enrollments​

Returns a paginated list of enrollments.

Filter examples:

  • filter=role='student' — only student enrollments
  • filter=user.sourcedId='USER_UUID' — enrollments for a specific student
  • filter=status='active' AND role='student' — active student enrollments

Scope: roster.readonly

Query params​

Standard pagination query params.

Response​

200 OK — { "enrollments": [...], "offset": 0, "limit": 100, "total": N }

Example​

curl "https://api.alpha-1edtech.ai/rostering/1.0/enrollments?filter=role%3D'student'" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

GET /rostering/1.0/enrollments/:sourcedId​

Returns a single enrollment by its sourcedId.

Scope: roster.readonly

Path params​

NameDescription
sourcedIdEnrollment UUID

Response​

200 OK — Enrollment object. 404 if not found.

Example​

curl "https://api.alpha-1edtech.ai/rostering/1.0/enrollments/66666666-6666-6666-6666-666666666666" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

PUT /rostering/1.0/enrollments/:sourcedId​

Create or update an enrollment using a standard OneRoster v1.2 Enrollment payload. Links a student to a class.

Required fields: sourcedId, status, dateLastModified, user (reference), class (reference), role.

The student and class must already exist. Create them first with PUT /users/{id} and PUT /classes/{id}.

Scope: roster.createput

Path params​

NameDescription
sourcedIdEnrollment UUID (must match body)

Request body​

Wrapped as { "enrollment": { ... } }.

FieldTypeRequiredDescription
sourcedIdstring (UUID)yesMust match the URL path parameter
dateLastModifiedstring (ISO 8601)yesTimestamp
user{ sourcedId }yesThe student being enrolled
class{ sourcedId }yesThe class to enroll in
rolestringyes"student", "teacher", "administrator", or "proctor"
primary"true" or "false"noWhether this is the primary enrollment
beginDatestringnoISO date when enrollment starts
endDatestringnoISO date when enrollment ends
metadataobjectnoAdditional metadata

Response​

201 Created or 200 OK — { "status": "...", "sourcedId": "..." }

Example​

curl -X PUT "https://api.alpha-1edtech.ai/rostering/1.0/enrollments/66666666-6666-6666-6666-666666666666" \
-H "Authorization: Bearer <ACCESS_TOKEN>" \
-H "Content-Type: application/json" \
-d '{
"enrollment": {
"sourcedId": "66666666-6666-6666-6666-666666666666",
"dateLastModified": "2026-01-15T00:00:00.000Z",
"user": { "sourcedId": "22222222-2222-2222-2222-222222222222" },
"class": { "sourcedId": "55555555-5555-5555-5555-555555555555" },
"role": "student"
}
}'

DELETE /rostering/1.0/enrollments/:sourcedId​

Soft-deletes an Enrollment. Returns HTTP 204.

Ownership: enforced via the Enrollment → Class → Course chain. If the Enrollment's Course is not owned by your client, the DELETE is rejected with HTTP 403.

Scope: roster.createput

Path params​

NameDescription
sourcedIdEnrollment UUID

Response​

204 No Content on success. 403 — ownership violation. 404 — not found.

Example​

curl -X DELETE "https://api.alpha-1edtech.ai/rostering/1.0/enrollments/66666666-6666-6666-6666-666666666666" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

GET /rostering/1.0/orgs​

Returns a paginated list of organizations (schools and districts). Use the org sourcedId when creating users, courses, and classes.

Filter examples:

  • filter=type='school' — only schools
  • filter=name~'Alpha' — orgs with "Alpha" in the name

Scope: roster.readonly

Query params​

Standard pagination query params.

Response​

200 OK — { "orgs": [...], "offset": 0, "limit": 100, "total": N }

Each org includes: sourcedId, name, type, identifier, parent.

Example​

curl "https://api.alpha-1edtech.ai/rostering/1.0/orgs" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

GET /rostering/1.0/orgs/:sourcedId​

Returns a single organization by its sourcedId.

Scope: roster.readonly

Path params​

NameDescription
sourcedIdOrganization UUID

Response​

200 OK — Org object. 404 if not found.

Example​

curl "https://api.alpha-1edtech.ai/rostering/1.0/orgs/ORG_SOURCED_ID" \
-H "Authorization: Bearer <ACCESS_TOKEN>"

GET /rostering/1.0/terms​

Returns a paginated list of academic-session terms. This is a partner-friendly view onto OneRoster academic sessions with type='term' always pinned — only term records are returned, never grading periods or school years.

Use term sourcedId values when populating terms on a class via PUT /classes/{id}.

Filter examples:

  • filter=schoolYear='2026' — terms in the 2026 school year
  • filter=title~'Fall' — terms with "Fall" in the title
  • filter=startDate>='2026-01-01' AND endDate<='2026-06-30' — terms inside a date window

A caller-supplied type filter that conflicts with type='term' (e.g., type='gradingPeriod') will return an empty result set.

Scope: roster.readonly

Query params​

Standard pagination query params.

Response​

200 OK — { "terms": [...], "offset": 0, "limit": 100, "total": N }

Each term includes: sourcedId, title, type (always "term"), startDate, endDate, schoolYear, org.

Example​

curl "https://api.alpha-1edtech.ai/rostering/1.0/terms?filter=schoolYear%3D'2026'" \
-H "Authorization: Bearer <ACCESS_TOKEN>"