Documentation Index
Fetch the complete documentation index at: https://docs.timeback.com/llms.txt
Use this file to discover all available pages before exploring further.
Overview
The OneRoster client provides access to the OneRoster 1.2 API, supporting:
- Rostering: Users, orgs, schools, courses, classes, enrollments
- Gradebook: Categories, line items, results, score scales
- Assessment: Assessment line items and results
- Resources: Learning resources linked to courses
Installation
npm install @timeback/oneroster
Quick Start
import { OneRosterClient } from '@timeback/oneroster'
const client = new OneRosterClient({
env: 'staging',
auth: {
clientId: process.env.ONEROSTER_CLIENT_ID!,
clientSecret: process.env.ONEROSTER_CLIENT_SECRET!,
},
})
const { data: students, hasMore } = await client.users.list({ where: { role: 'student' } })
const user = await client.users.get('user-123')
Rostering
Users
client.users.list()
client.users.list({ where: { role: 'teacher' } })
client.users.first({ where: { role: 'administrator' } })
client.users.listAll()
client.users.get(userId)
client.users.exists(userId)
client.users.create({ givenName, familyName, email, role })
client.users.update(userId, { givenName })
client.users.upsert(userId, { givenName, familyName, email, role })
client.users.delete(userId)
| Method | Returns | Description |
|---|
list() | PageResult | List users (supports where filter) |
first() | User | undefined | Get first matching user |
listAll() | User[] | Fetch all pages |
get() | User | Get user by ID |
exists() | boolean | Check if user exists (lightweight) |
create() | CreateResponse | Create user (returns sourcedIdPairs) |
update() | void | Update user (throws if not found) |
upsert() | void | Create or update user |
delete() | void | Delete user |
exists(), update(), and upsert() are available on all writable OneRoster resources.
update(id, data): strict (throws if the resource doesn’t exist)
upsert(id, data): loose (creates the resource if it doesn’t exist)
exists(id): lightweight existence check
Scoped User Operations
Access user-specific data using the callable pattern:
client.users('user-123').demographics()
client.users('user-123').classes()
client.users('user-123').resources()
client.users('user-123').agents()
client.users('user-123').agentFor()
client.users('user-123').addAgent({ sourcedId: 'parent-123', role: 'parent' })
client.users('user-123').removeAgent('parent-123')
client.users('user-123').createCredential({ type: 'username', username: 'johndoe' })
client.users('user-123').decryptCredential('cred-id')
Students & Teachers
Dedicated read-only resources for role-specific queries:
client.students.list()
client.students.get(studentId)
client.students(studentId).classes()
client.teachers.list()
client.teachers.get(teacherId)
client.teachers(teacherId).classes()
Schools & Organizations
client.schools.list()
client.schools.get(schoolId)
client.orgs.list()
// Nested resources
client.schools('school-id').classes()
client.schools('school-id').courses()
client.schools('school-id').terms()
client.schools('school-id').teachers()
client.schools('school-id').students()
client.schools('school-id').enrollments()
client.schools('school-id').scoreScales()
client.schools('school-id').lineItems()
// Deeply nested
client.schools('school-id').class('class-id').teachers()
client.schools('school-id').class('class-id').students()
client.schools('school-id').class('class-id').enrollments()
Courses & Classes
client.courses.list()
client.courses(courseId).classes()
client.courses(courseId).resources()
client.courses.components()
client.courses.getComponent(componentId)
client.courses.componentResources()
client.courses.getComponentResource(resourceId)
client.courses.createStructure({ ... })
client.classes.get(classId)
client.classes(classId).students()
client.classes(classId).teachers()
client.classes(classId).enrollments()
client.classes(classId).lineItems()
client.classes(classId).results()
client.classes(classId).categories()
client.classes(classId).scoreScales()
client.classes(classId).resources()
client.classes(classId).enroll({ sourcedId: userId, role: 'student' })
// Deeply nested gradebook
client.classes(classId).lineItem(lineItemId).results()
client.classes(classId).student(studentId).results()
Enrollments
client.enrollments.list()
client.enrollments.list({ where: { status: 'active' } })
client.enrollments.get(enrollmentId)
client.enrollments.create({ user, class, role })
client.enrollments.patch(enrollmentId, { status: 'tobedeleted' })
Terms & Academic Sessions
client.terms.list()
client.terms(termId).classes()
client.terms(termId).gradingPeriods()
client.academicSessions.list()
client.gradingPeriods.list()
Demographics
client.demographics.list()
client.demographics.get(demographicId)
Gradebook
Gradebook resources are top-level on the client:
// Core reads
await client.categories.list()
await client.lineItems.get(lineItemId)
await client.results.list()
// Gradebook writes return updated entities
const updatedCategory = await client.categories.update(categoryId, { title: 'Homework 2.0' })
const upsertedLineItem = await client.lineItems.upsert(lineItemId, lineItemInput)
// Assessment writes also return updated entities
const upsertedAssessmentResult = await client.assessmentResults.upsert(
assessmentResultId,
assessmentResultInput,
)
For gradebook + assessment resources, write methods return the entity:
update(id, data): strict (throws on 404), returns entity
upsert(id, data): loose (creates/updates), returns entity
For rostering + resources, write methods remain void.
| Resource family | update() / upsert() return |
|---|
| Rostering + Resources | void |
| Gradebook + Assessment | Updated entity |
Resources
client.resources.list()
client.resources.create({ ... })
client.resources('resource-id').export()
All list() methods return PageResult<T> with { data, hasMore, total, nextOffset }.
client.users.list({ offset?, limit? })
client.users.listAll(options?)
client.users.stream(options?)
| Method | Returns | Description |
|---|
list() | PageResult<T> | Single page with pagination info |
listAll() | T[] | Auto-fetches all pages |
stream() | AsyncIterable<T> | Memory-efficient streaming iterator |
Filtering
Use the where parameter to filter results:
client.users.list({ where: { role: 'student' } })
client.enrollments.list({ where: { status: 'active' } })
client.users.list({ where: { role: 'student', status: 'active' } })
Error Handling
import { OneRosterError } from '@timeback/oneroster'
try {
const user = await client.users.get('invalid-id')
} catch (error) {
if (error instanceof OneRosterError) {
console.log(error.statusCode) // 404
console.log(error.message) // 'Not Found'
}
}
Next Steps
EduBridge
Simplified analytics queries
Caliper
Learning event tracking
Types
OneRoster type definitions