WebUntis JSON-RPC + REST API client for Node.js (ESM, CJS, TypeScript).
Zero runtime dependencies. Requires Node.js 18+.
npm install untapiWebUntis URLs look like: https://[prefix].webuntis.com/WebUntis/
- server = the full hostname —
[prefix].webuntis.com - school = the subdomain prefix —
[prefix](usually matches)
Pass a full URL and the library parses it automatically:
import { WebUntis } from "untapi";
// Option A: pass server + school separately
const api = new WebUntis("[prefix].webuntis.com", "[prefix]");
// Option B: pass just the URL — school is auto-extracted
const api = new WebUntis("https://[prefix].webuntis.com/WebUntis/");
// Option C: pass server alone — library guesses the school name
const api = new WebUntis("[prefix].webuntis.com");Don't know the exact server? Use WebUntis.discover() — it probes all known WebUntis domains (.webuntis.com, .webuntis.de, .webuntis.at, .untis.at, etc.):
const info = await WebUntis.discover("[prefix]");
if (info) {
console.log(`Found: ${info.server} (${info.displayName})`);
const api = new WebUntis(info.server, info.school);
// ...
}const api = new WebUntis("[prefix].webuntis.com");
await api.login("your-username", "your-password");
// Fetch master data
const teachers = await api.masterData.getTeachers();
console.log(teachers);
// Fetch timetable for a class this week
const mon = WebUntis.thisMonday();
const fri = WebUntis.thisFriday();
const timetable = await api.timetable.forClass(42, mon, fri);
console.log(timetable);
await api.logout();All API modules are accessible as properties on the WebUntis instance:
| Method | Returns | Description |
|---|---|---|
getTeachers() |
MasterRef[] |
All teachers |
getStudents() |
MasterRef[] |
All students |
getKlassen() |
MasterRef[] |
All classes |
getSubjects() |
MasterRef[] |
All subjects |
getDepartments() |
Department[] |
All departments |
getRooms() |
MasterRef[] |
All rooms |
getSchoolyears() |
Schoolyear[] |
All school years |
getCurrentSchoolyear() |
Schoolyear |
Current school year |
getSchoolyearByDate(date) |
Schoolyear |
School year for a given date |
getHolidays() |
Holiday[] |
All holidays |
getHolidaysForRange(start, end) |
Holiday[] |
Holidays in a date range |
getTimegrid() |
Timegrid |
Lesson time slots |
getAll() |
MasterData |
All master data in parallel |
searchPerson(term) |
{ teachers, students } |
Search by name |
getPersonIds(ids) |
Person[] |
Resolve person IDs to names |
getClassTeachers(classId?) |
ClassTeacher[] |
Class teacher assignments |
getSubjectTeachers(subjectId?) |
SubjectTeacher[] |
Subject teacher assignments |
getStudentGroupMembers(groupId) |
StudentGroupMember[] |
Members of a student group |
| Method | Returns | Description |
|---|---|---|
getTimetable(element, start, end, opts?) |
TimetableEntry[] |
Core timetable query |
getTimetableWithAbsences(element, start, end) |
TimetableEntryWithAbsence[] |
Includes absence data |
getTimetableChanges(start, end, element?) |
TimetableChange[] |
Changes since last import |
forClass(id, start, end) |
TimetableEntry[] |
Shorthand: class timetable |
forTeacher(id, start, end) |
TimetableEntry[] |
Shorthand: teacher timetable |
forStudent(id, start, end) |
TimetableEntry[] |
Shorthand: student timetable |
forSubject(id, start, end) |
TimetableEntry[] |
Shorthand: subject timetable |
forRoom(id, start, end) |
TimetableEntry[] |
Shorthand: room timetable |
thisWeekForClass(id) |
TimetableEntry[] |
This week's class timetable |
thisWeekForTeacher(id) |
TimetableEntry[] |
This week's teacher timetable |
Element types (for getTimetable):
import { ElementType } from "untapi";
api.timetable.getTimetable(
{ id: 42, type: ElementType.Class }, // or 1-5
WebUntis.dateToInt(new Date(2026, 5, 8)),
WebUntis.dateToInt(new Date(2026, 5, 12)),
);| ElementType | Value |
|---|---|
ElementType.Class |
1 |
ElementType.Teacher |
2 |
ElementType.Subject |
3 |
ElementType.Student |
4 |
ElementType.Room |
5 |
| Method | Returns | Description |
|---|---|---|
getExams() |
Exam[] |
All exams |
getExamsForRange(start, end, opts?) |
Exam[] |
Exams in a date range |
forClass(id, start, end) |
Exam[] |
Exams for a class |
forStudent(id, start, end) |
Exam[] |
Exams for a student |
forTeacher(id, start, end) |
Exam[] |
Exams for a teacher |
| Method | Returns | Description |
|---|---|---|
getHomeworks(start, end, opts?) |
Homework[] |
Homework entries |
forClass(id, start, end) |
Homework[] |
Homework for a class |
forStudent(id, start, end) |
Homework[] |
Homework for a student |
forTeacher(id, start, end) |
Homework[] |
Homework by a teacher |
setCompleted(homeworkId, completed) |
boolean |
Mark as done/undone |
| Method | Returns | Description |
|---|---|---|
getAbsences(start, end, opts?) |
Absence[] |
Absence records |
forStudent(id, start, end) |
Absence[] |
Absences for a student |
forClass(id, start, end) |
Absence[] |
Absences for a class |
| Method | Returns | Description |
|---|---|---|
getSubstitutions(start, end, opts?) |
Substitution[] |
Substitution plans |
| Method | Returns | Description |
|---|---|---|
getClassregEvents(start, end, opts?) |
ClassregEvent[] |
Class register events |
forClass(id, start, end) |
ClassregEvent[] |
Events for a class |
| Method | Returns | Description |
|---|---|---|
getLatestImportTime() |
number (unix ms) |
Last data import timestamp |
getStatusData() |
StatusData |
Detailed sync status |
| Method | Returns | Description |
|---|---|---|
getMessages() |
Message[] |
All messages |
getMessagesSince(timestamp) |
Message[] |
Messages after timestamp |
WebUntis uses yyyymmdd integers for dates (e.g. 20260610 = 10 June 2026).
const d = WebUntis.dateToInt(new Date()); // 20260610
const date = WebUntis.intToDate(20260610); // Date object
const mon = WebUntis.thisMonday(); // this week's Monday
const fri = WebUntis.thisFriday(); // this week's Friday
const str = WebUntis.formatDate(20260610); // "10.6.2026"Also available as standalone imports:
import { dateToInt, intToDate, thisMonday, thisFriday } from "untapi";For methods not covered by the typed API:
const result = await api.client._request("getMethodName", { param: "value" });The library also ships a REST client (used by the WebUntis web app):
const data = await api.client._restRequest("timetable/entries?start=2026-06-08&end=2026-06-12&format=9&resourceType=STUDENT&resources=2627");Requires authentication via login() first (which captures the REST token).
import { WebUntisError, AuthenticationError, SessionExpiredError } from "untapi";
try {
await api.login("user", "pass");
} catch (err) {
if (err instanceof AuthenticationError) {
console.error("Bad credentials");
} else if (err instanceof SessionExpiredError) {
console.error("Session expired, re-login required");
} else if (err instanceof WebUntisError) {
console.error(`WebUntis error ${err.code}: ${err.message}`);
}
}| Error | Code | When |
|---|---|---|
AuthenticationError |
-8520 | Invalid credentials |
SessionExpiredError |
-8509 / -8510 | Session timed out |
InvalidRequestError |
— | Malformed request |
ServerError |
— | Server-side failure |
WebUntisError |
varies | Base class for all errors |
The library is fully typed — import types directly:
import type {
TimetableEntry, MasterRef, ElementType,
Schoolyear, Holiday, Exam, Homework, Absence,
Substitution, Message, StatusData,
} from "untapi";MIT