Skip to main content

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)
MethodReturnsDescription
list()PageResultList users (supports where filter)
first()User | undefinedGet first matching user
listAll()User[]Fetch all pages
get()UserGet user by ID
exists()booleanCheck if user exists (lightweight)
create()CreateResponseCreate user (returns sourcedIdPairs)
update()voidUpdate user (throws if not found)
upsert()voidCreate or update user
delete()voidDelete 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 familyupdate() / upsert() return
Rostering + Resourcesvoid
Gradebook + AssessmentUpdated entity

Resources

client.resources.list()
client.resources.create({ ... })
client.resources('resource-id').export()

Pagination

All list() methods return PageResult<T> with { data, hasMore, total, nextOffset }.
client.users.list({ offset?, limit? })
client.users.listAll(options?)
client.users.stream(options?)
MethodReturnsDescription
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