VISH app — RUT (MIIT) timetable

The timetable of the Russian University of Transport for students and staff of every institute. The timetable of your own group and of any teacher by day and week, free MIIT rooms right now, occupancy of rooms, groups and teachers, notifications about timetable changes and an AI timetable assistant.

Institutes

The RUT (MIIT) app covers five institutes: VISH — Higher Engineering School, AGA — Civil Aviation Academy, ADKH — Road Management Academy, PISH — Advanced Engineering School “HSR Academy” and IMTK — Institute of International Transport Communications. A group’s and a teacher’s timetable are searched the same way in any of them.

What the VISH app can do
Sections
Guide

Notifications and calendars

Updated 27.10.2026

How to find out about schedule changes without asking the API every minute. Checked with booth d1 on October 23, 2026; the methods of this page are also available on production.

What to choose

ProblemThan to solve
Schedule in Google Calendar, Apple Calendar, OutlookSubscription to calendar feed GET /calendar/schedule.ics
Exams and tests in the calendarGET /session.ics
Bot or service that reports changesPolls GET /schedule/changes every few minutes
A complete copy of the schedule at homeGET /schedule times an hour or two, a comparison of updatedAt
Push to the browserOnly for the application itself VISH — see below

Calendar Feed

GET /calendar/schedule.ics returns a schedule in iCalendar format with the same filters as GET /schedule: group or groupId, teacher or teacherId, scope, dateFrom, dateTo, and lessonIds and subjectIds (only these classes or subjects), locale (ru, en, zh) and attachment=1 (to give as a file).

  • You don't need a key: it's the same schedule that any visitor sees.
  • Subscribe to the address — the calendar itself rereads it and picks up edits, cancellations and deletions. Each activity has a constant UID, so the change updates the event rather than adding a second one.
  • Time is with the time zone (DTSTART;TZID=Europe/Moscow:…).
  • No more than 60 requests per minute from one address.
text
https://d1.vish-app.ru/api/v1/calendar/schedule.ics?group=ШАД-111

GET /session.ics is the same for the session.: exams, tests, and consultations with a group or teacher.

Change Feed

GET /schedule/changes — what has recently changed in the schedule of one group (groupId) or teacher (teacherId), new from above.

  • period=recent (by default) — recent changes; limit — how many.
  • period=weeks — changes in classes for this and next week.
  • At the record: lessonId, change (created, announced, updated, deleted), subject, room, startAt, endAt, changedFields, changes ( field, was, became), origin (institute — revision at the institute, source — new university schedule) and createdAt.

How to poll: once every 5-15 minutes, memorizing id or createdAt of the last processed record, and process only what is newer. The answer from period=weeks is cached for a minute — it's pointless to ask more often.

Push in the browser

POST /push/subscriptions and POST /push/unsubscribe subscribe the browser of application VISH to notifications about changes to the group or teacher; the public VAPID key for subscription is in GET /app-config (push.publicKey). These methods are designed for the application VISH itself: the subscription is created by its service worker. The change feed is more convenient for your site or bot.

The list of API methods could not be loadedOpen the API reference (opens in a new tab)

Example: feed and changes

The example downloads the calendar feed of a group, checks its format and uniqueness UID, and then reads the changes of this and next week. The group is VISH_GROUP, with ШАД-111 by default.

// The group's calendar feed and its recent changes; no key needed.
const API = process.env.VISH_API ?? 'https://d1.vish-app.ru/api/v1'
const GROUP = process.env.VISH_GROUP ?? 'ШАД-111'

const groups = await (await fetch(`${API}/groups?search=${encodeURIComponent(GROUP)}&all=1`)).json()
const group = groups.list.find((item) => item.name === GROUP)
if (!group) throw new Error(`group ${GROUP} not found`)

const feed = await fetch(`${API}/calendar/schedule.ics?group=${encodeURIComponent(GROUP)}`)
const calendar = await feed.text()
if (!feed.ok || !feed.headers.get('content-type')?.startsWith('text/calendar') || !calendar.startsWith('BEGIN:VCALENDAR')) {
	throw new Error(`not a calendar: HTTP ${feed.status}`)
}
const uids = [...calendar.matchAll(/^UID:(.+)$/gmu)].map((match) => match[1].trim())
if (new Set(uids).size !== uids.length) throw new Error('duplicate UIDs')

const response = await fetch(`${API}/schedule/changes?groupId=${group.id}&period=weeks`)
if (!response.ok) throw new Error(`changes: HTTP ${response.status}`)
const changes = (await response.json()).list
if (!Array.isArray(changes) || changes.some((item) => !item.lessonId || !item.change || !item.createdAt)) {
	throw new Error('unexpected changes answer')
}

console.log(`${GROUP}: ${uids.length} events in the feed, ${changes.length} changes this week and next`)
for (const item of changes.slice(0, 5)) {
	console.log(`- ${item.createdAt.slice(0, 16)} ${item.change}: ${item.subject?.ru ?? item.lessonId} (${item.changedFields?.join(', ') ?? ''})`)
}

To try

The current week, the call grid, and the public key for push:

Try the request

Only methods with a lock need a key. It lives on this page only: it is never stored, goes out only as a header of this request and is forgotten when you leave. Where to get a key

Verified: 2026-10, PWA aa337c45, platform bff65fce._