Unofficial TypeScript SDK for IServ school management servers. Authenticate with username and password, no API key required.
npm install iserv-apiimport { IServAPI } from "iserv-api";
const api = await IServAPI.connect("your-school.iserv.de", "username", "password");
const info = await api.users.getOwnInfo();
console.log(info);
await api.disconnect();- Installation
- Basic usage
- Supported functionality
- Logging
- License
const info = await api.users.getOwnInfo();Returns name, email, groups, roles, rights, and public profile info of the logged-in user.
await api.users.setOwnInfo({
nickname: "Ali",
city: "Berlin",
hidden: false,
});Available fields: title, company, birthday, nickname, schoolClass, street, zipcode, city, country, phone, mobilePhone, fax, mail, homepage, icq, jabber, msn, skype, note, hidden
const data = await api.notifications.getAll();Returns all notifications including unread count and notification items.
const badges = await api.notifications.getBadges();Returns sidebar badge counts (e.g. unread email count).
await api.notifications.readAll();Marks all notifications as read.
await api.notifications.read(123);Marks a single notification as read by its ID.
await api.users.getProfilePicture("alice", "./avatars");Saves the user's profile picture to the specified folder as {username}.{ext}.
const buffer = await api.users.getProfilePictureBuffer("alice");
const buffer = await api.users.getProfilePictureBuffer("alice", 128, 128);Returns the profile picture as a Buffer. Width and height must be positive integers between 1 and 4096.
const info = await api.users.getInfo("alice");Returns the public address book information of any user.
const results = await api.users.search("Alice");Searches the address book. Returns an array of { name, userUrl }.
const results = await api.users.searchAutocomplete("ali", 10);Faster autocomplete search. Returns up to limit results (default 50).
const emails = await api.email.getEmails({
mailbox: "INBOX",
limit: 25,
offset: 0,
sort: "date",
order: "desc",
});const message = await api.email.getMessage(uid, "INBOX");Returns the full message including headers, body parts, and attachment metadata.
await api.email.sendEmail({
to: "[email protected]",
subject: "Hello",
body: "Plain text body",
htmlBody: "<p>HTML body</p>",
smtpsPort: 465,
attachments: ["./file.pdf"],
});Attachments must be relative paths. smtpsPort must be 465 or 587.
const { events } = await api.calendar.getUpcomingEvents();const sources = await api.calendar.getEventSources();Returns all available calendars and plugins. Each source has an id, label, and type ("cal" or "plugin").
const events = await api.calendar.getEvents("2025-01-01", "2025-12-31");Returns all events across all sources in the given time range.
const results = await api.calendar.searchEvents("Math exam", "2025-01-01", "2025-12-31");const events = await api.calendar.getPluginEvents("holiday", "2025-01-01", "2025-12-31");Plugin IDs come from event sources where type === "plugin".
const result = await api.calendar.createEvent({
subject: "Math exam",
calendar: "/alice/home",
start: "2025-09-27T14:00:00",
end: "2025-09-27T16:00:00",
location: "Room 101",
description: "Bring calculator",
alarms: ["1D", "2H"],
isAllDayLong: false,
participants: ["bob", "[email protected]"],
showMeAs: "OPAQUE",
privacy: "PUBLIC",
recurring: {
intervalType: "WEEKLY",
interval: 1,
recurrenceDays: ["MO", "WE"],
endType: "COUNT",
endInterval: 10,
},
});Alarm types:
Preset strings: "0M" "5M" "15M" "30M" "1H" "2H" "12H" "1D" "2D" "7D"
Custom datetime alarm:
{ custom_date_time: { dateTime: "2025-09-26T10:00:00" } }Custom interval alarm:
{
custom_interval: {
interval: { days: 1, hours: 2, minutes: 0 },
before: true,
}
}Recurring options:
| Field | Type | Description |
|---|---|---|
intervalType |
"NO" | "DAILY" | "WEEKDAYS" | "WEEKLY" | "MONTHLY" | "YEARLY" |
Repeat pattern |
interval |
number |
Repeat every N units (required for most types) |
recurrenceDays |
WeekDay[] |
Required for WEEKLY |
monthlyIntervalType |
"BYMONTHDAY" | "BYDAY" |
Required for MONTHLY |
endType |
"NEVER" | "COUNT" | "UNTIL" |
How the recurrence ends |
endInterval |
number |
Required if endType is "COUNT" |
untilDate |
string |
Required if endType is "UNTIL", format "DD.MM.YYYY" |
await api.calendar.deleteEvent({
uid: "[email protected]",
hash: "541f2d74099d785d1286c03903a2e826",
calendar: "/alice/home",
start: "2025-09-27T14:00:00+02:00",
series: false,
});uid, hash, calendar, and start are returned by getEvents().
const client = api.files.getClient();Returns a pre-authenticated webdav client. See the webdav package documentation for all available methods.
const files = await client.getDirectoryContents("/");
await client.putFileContents("/notes.txt", "hello");
const data = await client.getFileContents("/notes.txt");const size = await api.files.getFolderSize("/Documents");const usage = await api.files.getDiskSpace();Returns disk space info for all accessible storage volumes (label, free space, color).
The messenger service wraps the Matrix protocol used by IServ. A Matrix session is established automatically during login.
const rooms = await api.messenger.getRooms();Returns all joined rooms (group chats and direct messages).
Each room has:
| Field | Type | Description |
|---|---|---|
id |
string |
Matrix room ID |
name |
string |
Room name or display name of the other person |
isDirect |
boolean |
Whether this is a DM |
unreadCount |
number |
Unread message count |
lastMessage |
RoomLastMessage | null |
Most recent message |
lastMessage fields: body, sender (Matrix user ID), senderName (display name or null), timestamp.
const { messages, start, end } = await api.messenger.getMessages(roomId, { limit: 30, from: end });Returns up to limit messages (default 30) in reverse chronological order. Pass end from a previous response as from to paginate backwards. end is undefined when there are no more messages.
Each message has:
| Field | Type | Description |
|---|---|---|
eventId |
string |
Matrix event ID |
sender |
string |
Matrix user ID |
senderName |
string | null |
Display name |
body |
string |
Message text, empty string if the message is end-to-end encrypted |
msgtype |
string |
e.g. "m.text", "m.image", "m.file" — "m.encrypted" for E2EE messages |
timestamp |
number |
Unix ms |
encrypted |
boolean |
true if the message content cannot be decrypted by this SDK |
const { messages } = await api.messenger.getMessagesByName("Max Mustermann", { limit: 20 });Looks up the room by name and returns its messages. Throws if no room or multiple rooms match the name. Accepts the same options as getMessages().
const members = await api.messenger.getMembers(roomId);Returns all current members of a room (excludes users who have left).
Each member has: userId, displayName, avatarUrl, membership ("join" | "invite" | "ban" | "knock").
const profile = await api.messenger.getProfile(userId);Returns the Matrix profile of any user: userId, displayName, avatarUrl.
const health = await api.conference.getHealth();Returns the health status of the IServ video conference endpoint.
The SDK logs to stderr using a built-in logger. Set ISERV_DEBUG=1 to enable debug output:
ISERV_DEBUG=1 node app.jsMIT
Disclaimer: This is an unofficial SDK not affiliated with IServ GmbH. Use at your own risk. The authors are not responsible for any damages or data loss caused by use of this package.