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.

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>"