Get Timetable
Retrieve one timetable in full: its bell schedules, entities, lessons and every lesson unit.
Endpoint
GET /api/v1/timetables/{id}
ERP partners read timetables at GET /api/partner/v1/timetables/{id}. See
Reading schedules.
Authentication
Authorization: Bearer ttm_YOUR_API_KEY
See Authentication.
Path parameters
| Parameter | Type | Description |
|---|---|---|
id | string | Timetable id, from List Timetables |
How the response fits together
- Bell schedules define the days and periods. A placement is a
(dayId, periodIndex)pair. - Entities (teachers, subjects, classes, rooms) are listed once each.
- Lessons say who teaches what to whom. Lesson units are the individual scheduled periods of a lesson.
Every reference in the response (a unit's teachers, a class's class teacher, a section's
students) is a localId, and every localId it references is listed in the same response. To
render a grid, walk lessonUnits, place each at its (dayId, periodIndex), and look up its
teacherIds, classIds, subjectIds and roomIds in the entity lists.
Identifiers
Each entity carries three identifiers:
| Field | Scope | Use it for |
|---|---|---|
localId | This timetable response | Joining references to entities. Every *Ids field holds these |
entityId | Your organisation, across all timetables | Recognising the same teacher, class or room in another timetable or version |
externalId | Your own systems | Joining to your own records (a staff number, a student MIS id). null when none is kept |
Prefixes tell the entity type apart: tch_ teacher, cls_ class, sub_ subject, rom_ room,
stu_ student, crs_ course. Treat the rest of an id as opaque.
Response
{
"success": true,
"data": {
"id": "6a34108b1d16898202940188",
"name": "Term 1 2026",
"groupId": "6a3410551d16898202940101",
"versionNumber": 3,
"versionName": null,
"status": "published",
"isCurrent": true,
"publishedAt": "2026-08-28T07:15:00.000Z",
"effectiveFrom": 20260901,
"effectiveTo": null,
"schedulingMode": "standard",
"createdAt": "2026-07-01T09:12:00.000Z",
"updatedAt": "2026-08-28T07:15:00.000Z",
"description": "",
"orgId": "6913a0c4e1b2f3a4b5c6d7e8",
"bellSchedule": { "id": "bs_6a34108b1d16898202940188", "name": "Main", "isDefault": true, "…": "…" },
"bellSchedules": [
{
"id": "bs_6a34108b1d16898202940188",
"name": "Main",
"isDefault": true,
"scheduleType": "weekly",
"cycleLength": 1,
"days": [
{ "id": "day_w_0_d_1", "label": "Monday", "shortLabel": "Mon", "dayOfWeek": 1, "weekInCycle": null }
],
"dayConfigurations": [
{
"id": "dc1",
"dayIds": ["day_w_0_d_1"],
"periods": [
{ "id": "p1", "name": "Period 1", "startTime": "08:30", "endTime": "09:15" },
{ "id": "p2", "name": "Period 2", "startTime": "09:15", "endTime": "10:00" }
],
"breaks": [
{ "id": "b1", "name": "Break", "startTime": "10:00", "endTime": "10:20", "followsPeriodIndex": 1 }
]
}
]
}
],
"teachers": [
{ "localId": "tch_68d0f1…", "entityId": "68d0f1…", "externalId": "EMP-1001",
"name": "Ada Sharma", "shortName": "AS", "color": "#3B82F6", "isActive": true, "maxPeriods": 6 }
],
"subjects": [
{ "localId": "sub_6923ab…", "entityId": "6923ab…", "externalId": null,
"name": "Mathematics", "shortName": "Math", "color": "#10B981", "isActive": true }
],
"classes": [
{ "localId": "cls_6911cd…", "entityId": "6911cd…", "externalId": null,
"name": "Grade 9A", "shortName": "9A", "color": null, "isActive": true,
"classTeacherId": "tch_68d0f1…", "bellScheduleId": null }
],
"rooms": [
{ "localId": "rom_6930ef…", "entityId": "6930ef…", "externalId": null,
"name": "Science Lab", "shortName": "Lab", "color": null, "isActive": true,
"capacity": 30, "buildingName": "Main Block" },
{ "localId": "rom_6930f0…", "entityId": "6930f0…", "externalId": null,
"name": "Physics Lab", "shortName": "Phy", "color": null, "isActive": true,
"capacity": 28, "buildingName": "Main Block" }
],
"roomGroups": [
{ "id": "rgp_6a01c2…", "entityId": "6a01c2…", "name": "Science Labs",
"memberIds": ["rom_6930ef…", "rom_6930f0…"] }
],
"lessons": [
{
"localId": "lsn_cecf12…",
"groups": [
{ "id": "g1", "name": null,
"teacherIds": ["tch_68d0f1…"], "classIds": ["cls_6911cd…"], "subjectIds": ["sub_6923ab…"],
"studentIds": [],
"roomMode": "any", "roomIds": [], "roomCandidateIds": [],
"roomGroupIds": ["rgp_6a01c2…"], "roomVariation": "same" }
],
"lessonConfigurations": [ { "id": "cfg1", "frequency": 2, "length": 2 } ],
"distributionGroupId": null
}
],
"lessonUnits": [
{
"localId": "lu_0001…",
"lessonLocalId": "lsn_cecf12…",
"sectionLocalId": null,
"dayId": "day_w_0_d_1",
"periodIndex": 0,
"spanId": "sp_91…",
"parallelGroupId": null,
"groupName": null,
"parallelGroupName": null,
"distributionGroupId": null,
"lessonGroupId": "g1",
"roomPickedBy": "system",
"locked": false,
"lockReason": null,
"teacherIds": ["tch_68d0f1…"],
"classIds": ["cls_6911cd…"],
"subjectIds": ["sub_6923ab…"],
"roomIds": ["rom_6930ef…"],
"studentIds": []
}
]
},
"timestamp": "2026-10-06T10:00:00.000Z"
}
Version fields
| Field | Notes |
|---|---|
id | This version. Pass it back to this endpoint |
name | The timetable's name, shared by all its versions |
groupId | Shared by every version of the same timetable |
versionNumber, versionName | Which version this is. versionName is null unless one was given |
status | draft or published. Only show published timetables to staff and students |
isCurrent | true for the version currently in use |
publishedAt | When it was published, null for a draft |
effectiveFrom, effectiveTo | The dates a published version applies, as YYYYMMDD numbers. effectiveTo: null means open-ended |
schedulingMode | standard (class-based) or student-level (see below) |
Bell schedules
bellSchedules lists every bell schedule the timetable uses, the default first.
bellSchedule is the default one, repeated for readers that only need one.
| Field | Notes |
|---|---|
id | Referenced by a class's bellScheduleId |
isDefault | true for the schedule every class runs on unless it names another |
scheduleType, cycleLength | weekly, or a cycle of cycleLength weeks |
days[].id | What a lesson unit's dayId refers to. weekInCycle tells weeks of a cycle apart |
dayConfigurations | Which periods and breaks apply on which days. Days can differ |
periods[] | In order. A unit's periodIndex is the position in this list (0-based) |
breaks[].followsPeriodIndex | The period a break comes after |
A class with bellScheduleId: null runs on the default schedule. Read a unit's period times from
the schedule of the class it belongs to.
Entity fields
| Field | Notes |
|---|---|
localId, entityId, externalId | See Identifiers |
isActive | false for an entity removed from the organisation but still used by this timetable |
maxPeriods | Teachers: the most periods per scheduling cycle (student-level scheduling), null when not set |
classTeacherId | Classes: the class teacher's localId |
bellScheduleId | Classes: the bell schedule the class runs on, null for the default |
capacity, buildingName | Rooms |
An entity that a lesson still references but that no longer exists in your organisation is listed
with the name Unknown, so every reference still leads somewhere.
Room groups
roomGroups[] lists the room groups this timetable's lessons use: rooms that can stand in for one
another ("Science Labs"). A room can be in several groups.
| Field | Notes |
|---|---|
id | What lesson groups and courses reference in roomGroupIds (rgp_…) |
entityId | The group in your organisation, stable across timetables |
name | The group's name |
memberIds | The rooms in the group, by localId; every one is listed in rooms |
A published timetable keeps the groups as they were when it was published.
Lesson fields
| Field | Notes |
|---|---|
groups[] | Who is taught. Most lessons have one group; a split or parallel lesson has several, each with its own teachers, classes and rooms |
groups[].roomMode | What rooms the group needs: all (every room in roomIds, at once), any (one room from roomCandidateIds or from the rooms of the groups in roomGroupIds), or none |
groups[].roomIds | With all: the rooms needed. Empty otherwise |
groups[].roomCandidateIds, groups[].roomGroupIds | With any: the rooms and room groups to choose from |
groups[].roomVariation | With any: same (one room for every occurrence) or vary (the room may change from one occurrence to the next). A double period always stays in one room |
lessonConfigurations[] | frequency (how many times a week) of length periods each. A lesson with frequency: 2, length: 2 is two double periods |
distributionGroupId | Lessons sharing this id are spread across the week as one, instead of each on its own |
Lesson unit fields
| Field | Notes |
|---|---|
lessonLocalId | The lesson this unit belongs to |
dayId, periodIndex | Placement. Both null when the unit could not be scheduled |
spanId | A double (or longer) period is several units sharing this id. Duration = how many share it |
parallelGroupId, parallelGroupName | Units taught at the same time (options blocks, split groups) |
groupName | Which group within a parallel block |
lessonGroupId | The id of the lesson group this unit teaches (lessons[].groups[]), where its room requirement is |
roomIds | The room the unit was given. For a lesson with roomMode: any this is the room picked for this occurrence |
roomPickedBy | For roomMode: any: system (picked by scheduling) or user (chosen by hand); null otherwise |
locked, lockReason | The unit was placed or pinned by hand |
teacherIds, classIds, subjectIds, roomIds, studentIds | References by localId |
There is no length field on a unit: a double period is two units sharing a spanId.
Student-level timetables
When schedulingMode is student-level, the response also includes:
| Field | Notes |
|---|---|
students[] | localId, entityId, externalId, name, shortName, color, classId (a class localId), courseIds (course localIds) |
courses[] | localId (crs_…), entityId, name, courseCode, teacherIds, roomIds, roomGroupIds, roomVariation and the course's scheduling settings |
sections[] | localId, name, courseLocalId, capacity, isAutoGenerated, parallelGroupId, teacherIds, roomIds, roomPickedBy, studentIds. When the course's roomVariation is vary, a section usually has no roomIds (each lesson unit has its own room); one with roomPickedBy: "user" has its lessons pinned to its room |
sectionSettings | How sections were generated |
A unit's sectionLocalId names its section, and its subjectIds can hold the section's course
(crs_…).
Example
curl -H "Authorization: Bearer ttm_YOUR_API_KEY" \
https://api.timetablemaster.com/api/v1/timetables/6a34108b1d16898202940188
Errors
| Status | Code | Meaning |
|---|---|---|
| 401 | INVALID_API_KEY | Missing, invalid, expired or revoked key, or API access is not enabled for your organisation |
| 402 | ACCESS_EXPIRED, ACCOUNT_SUSPENDED | Your organisation's access has ended or is suspended |
| 404 | TIMETABLE_NOT_FOUND | No such timetable, or it belongs to another organisation |
| 500 | INTERNAL_ERROR | Unexpected server error |
See Authentication errors for the response bodies.