Level 1: Student Onboarding
Programmatically create and manage students, users, and their relationships (parents, guardians) in TimeBack's roster.
What Student Onboarding Provides
Student onboarding enables your learning app to:
- Create and update student records in TimeBack's roster
- Manage user accounts with roles and profiles
- Link students to agents (parents, guardians, relatives)
- Query agent relationships for a user
This is foundational for apps that need to manage student data programmatically rather than relying solely on LTI authentication or manual registration.
Prerequisites
Before implementing student onboarding:
- Register your app (see Level 0: Registration)
- Request OAuth credentials with the
roster.createputscope (see Authentication Guide)
Implementation Guide
Step 1: Obtain Access Token
Request an access token with roster write permissions:
const response = await fetch('https://platform.timeback.com/auth/1.0/token', {
method: 'POST',
headers: {
'Content-Type': 'application/x-www-form-urlencoded',
Authorization: `Basic ${Buffer.from(`${clientId}:${clientSecret}`).toString('base64')}`,
},
body: new URLSearchParams({
grant_type: 'client_credentials',
scope: 'https://purl.imsglobal.org/spec/or/v1p2/scope/roster.createput',
}),
});
const { access_token } = await response.json();
Step 2: Create or Update a Student
Use the upsertStudent endpoint to create a new student or update an existing one:
PUT https://platform.timeback.com/rostering/1.0/students
Example request:
const studentData = {
student: {
sourcedId: 'student-uuid-here', // Your unique identifier for this student
status: 'active',
username: 'john.doe',
enabledUser: 'true',
givenName: 'John',
familyName: 'Doe',
middleName: null,
email: 'john.doe@example.com',
phone: null,
grades: ['5'],
primaryOrg: {
sourcedId: 'organization-uuid', // The school/org this student belongs to
type: 'org',
},
},
};
const response = await fetch('https://platform.timeback.com/rostering/1.0/students', {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify(studentData),
});
// Returns 200 OK on success
Required fields:
| Field | Type | Description |
|---|---|---|
sourcedId |
string | Unique identifier for the student |
status |
string | active, inactive, or tobedeleted |
username |
string | Login username |
enabledUser |
string | "true" or "false" (as strings) |
givenName |
string | Student's first name |
familyName |
string | Student's last name |
primaryOrg |
object | Reference to the student's primary organization |
grades |
string[] | Array of grade levels (e.g., ["5", "6"]) |
Step 3: Create or Update a User
For non-student users (teachers, parents, administrators), use the upsertUser endpoint:
PUT https://platform.timeback.com/rostering/1.0/users/{sourcedId}
Example request:
const userData = {
user: {
sourcedId: 'user-uuid-here',
status: 'active',
enabledUser: 'true',
givenName: 'Jane',
familyName: 'Smith',
email: 'jane.smith@example.com',
grades: [],
primaryOrg: {
sourcedId: 'organization-uuid',
type: 'org',
},
roles: [
{
roleType: 'primary',
role: 'parent',
org: {
sourcedId: 'organization-uuid',
type: 'org',
},
},
],
},
};
const response = await fetch(`https://platform.timeback.com/rostering/1.0/users/${userData.user.sourcedId}`, {
method: 'PUT',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify(userData),
});
// Returns 201 Created on success
Available roles:
student,teacher,parent,guardian,relativeaide,counselor,principal,proctordistrictAdministrator,siteAdministrator,systemAdministrator
Step 4: Link a Student to an Agent
Create relationships between students and their agents (parents, guardians):
PUT https://platform.timeback.com/rostering/1.0/students/{sourcedId}/agents/{agentId}
Example request:
const agentData = {
user: {
sourcedId: 'parent-user-uuid', // The agent's user ID
type: 'user',
},
relationshipType: 'parent', // free-form string describing the relationship
};
const response = await fetch(
`https://platform.timeback.com/rostering/1.0/students/${studentId}/agents/${agentRelationshipId}`,
{
method: 'PUT',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
body: JSON.stringify(agentData),
},
);
// Returns 201 Created on success
Relationship type:
The relationshipType is a free-form string. Use any value that describes the relationship in your system.
Step 5: Query User Agents
Retrieve all agents associated with a user:
GET https://platform.timeback.com/rostering/1.0/users/{sourcedId}/agents
Example request:
const response = await fetch(`https://platform.timeback.com/rostering/1.0/users/${userId}/agents`, {
method: 'GET',
headers: {
'Content-Type': 'application/json',
Authorization: `Bearer ${accessToken}`,
},
});
const data = await response.json();
// Returns: { agents: [{ user: { sourcedId, type }, relationshipType }] }
Step 6: Remove an Agent Relationship
Delete an agent relationship when it's no longer valid:
DELETE https://platform.timeback.com/rostering/1.0/students/{sourcedId}/agents/{agentId}
Example request:
const response = await fetch(
`https://platform.timeback.com/rostering/1.0/students/${studentId}/agents/${agentRelationshipId}`,
{
method: 'DELETE',
headers: {
Authorization: `Bearer ${accessToken}`,
},
},
);
// Returns 204 No Content on success
Required Scopes
| Operation | Required Scope |
|---|---|
upsertStudent |
https://purl.imsglobal.org/spec/or/v1p2/scope/roster.createput |
upsertUser |
https://purl.imsglobal.org/spec/or/v1p2/scope/roster.createput |
upsertStudentAgent |
https://purl.imsglobal.org/spec/or/v1p2/scope/roster.createput |
deleteStudentAgent |
https://purl.imsglobal.org/spec/or/v1p2/scope/roster.createput |
getUserAgents |
https://purl.imsglobal.org/spec/or/v1p2/scope/roster.readonly |
Common Pitfalls
Not matching sourcedId in path and body
// ❌ Bad: Path and body sourcedId don't match
await fetch('/rostering/1.0/users/user-123', {
body: JSON.stringify({ user: { sourcedId: 'user-456', ... } }),
});
// ✅ Good: Path and body sourcedId match
await fetch('/rostering/1.0/users/user-123', {
body: JSON.stringify({ user: { sourcedId: 'user-123', ... } }),
});
Using boolean instead of string for enabledUser
// ❌ Bad: Boolean value
{
enabledUser: true;
}
// ✅ Good: String value
{
enabledUser: 'true';
}
Missing required organization reference
// ❌ Bad: Missing primaryOrg
{ student: { sourcedId: '...', givenName: 'John', ... } }
// ✅ Good: Include primaryOrg
{
student: {
sourcedId: '...',
givenName: 'John',
primaryOrg: { sourcedId: 'org-uuid', type: 'org' },
...
}
}
Related Docs
Level 0: Registration
Register your app first to get OAuth credentials for API access.
Level 2: LTI Launch
Implement seamless authentication so students can access your app without credentials.
Level 3: Caliper Events
Send learning activity events to unlock coaching insights and unified analytics.
Authentication
Detailed guide on obtaining and managing OAuth access tokens.