Приложение ВИШ — расписание РУТ (МИИТ)

Расписание Российского университета транспорта для студентов и сотрудников всех институтов. Расписание своей группы и любого преподавателя на день и на неделю, свободные аудитории МИИТ прямо сейчас, загруженность аудиторий, групп и преподавателей, уведомления об изменениях в расписании и ИИ-помощник по расписанию.

Институты

Приложение РУТ (МИИТ) охватывает пять институтов: ВИШ — Высшая инженерная школа, АГА — Академия гражданской авиации, АДХ — Академия дорожного хозяйства, ПИШ — Передовая инженерная школа «Академия ВСМ» и ИМТК — Институт международных транспортных коммуникаций. Расписание группы и расписание преподавателя ищутся одинаково в любом из них.

Что умеет приложение ВИШ
Разделы
Руководство

Разработчикам: начало работы

Обновлено 27.10.2026

У ВИШ открытый HTTP API: им пользуется само приложение, и им же могут пользоваться ваши скрипты, боты и сайты. Расписание, группы, преподаватели и аудитории читаются без всякого ключа; ключ нужен, чтобы действовать от своего имени, а «Вход через ВИШ» — чтобы читать данные другого человека с его согласия.

Эта страница — с чего начать. Остальные страницы раздела «Разработчикам» разбирают отдельные части API. Сверено со стендом d1 и production 23 октября 2026 года.

Адреса стендов

СтендБазовый адрес APIДокументация OpenAPI
d1 (тестовый)https://d1.vish-app.ru/api/v1https://d1.vish-app.ru/documentation
productionhttps://api.vish-app.ru/api/v1 (или https://www.vish-app.ru/api/v1)https://www.vish-app.ru/documentation
  • d1 — тестовый стенд: новые функции появляются здесь раньше, данные могут меняться. Начинайте с него.
  • production — то, чем пользуются студенты. Новое попадает сюда релизом раз в две недели.
  • Адрес без www (https://vish-app.ru) отвечает перенаправлением 301 — указывайте полный адрес, иначе часть библиотек потеряет заголовки при переходе.
  • Машинное описание всех методов — /documentation/json на том же стенде (OpenAPI 3).

Во всех примерах раздела адрес берётся из переменной окружения VISH_API (по умолчанию d1), а ключ — из VISH_API_KEY. Не вписывайте ключ в код.

Первый запрос

Ключ не нужен: список институтов и групп открыт всем.

// List institutes and the first groups; no key needed.
const API = process.env.VISH_API ?? 'https://d1.vish-app.ru/api/v1'

const get = async (path) => {
	const response = await fetch(`${API}${path}`, { headers: { Accept: 'application/json' } })
	if (!response.ok) throw new Error(`${path}: HTTP ${response.status}`)
	return response.json()
}

const institutes = await get('/institutes')
if (!Array.isArray(institutes.list) || institutes.list.length === 0) throw new Error('no institutes')

const groups = await get('/groups?perPage=3')
if (groups.list.length === 0 || typeof groups.meta?.total !== 'number') throw new Error('unexpected /groups')

console.log(`${institutes.list.length} institutes, ${groups.meta.total} groups`)
for (const group of groups.list) console.log(group.name, '—', group.institute?.code)

Попробовать прямо здесь:

Попробовать запрос

Ключ нужен только методам с замком. Он живёт только на этой странице: не сохраняется, уходит лишь заголовком этого запроса и забывается, когда вы её покинете. Где взять ключ

Как устроены ответы

  • Всё — JSON в UTF-8. Даты — ISO 8601 в UTC (2026-10-19T13:45:00.000Z).
  • Списки приходят как { "list": [...], "meta": { "total", "page", "perPage", "pages" } }. Страница задаётся page (с 1) и perPage (по умолчанию 20, не больше 200). У списков есть all=1 — всё одной страницей, но не больше 2000 записей.
  • Названия, которые переводятся, приходят объектом { "ru": "…", "en": "…", "zh": "…" }; русский есть всегда, перевод может отсутствовать.
  • Новые поля в ответах появляются без предупреждения — не падайте на незнакомых полях.

Ключ доступа

Для чтения открытых данных ключ не нужен. Он нужен, когда скрипт действует от вашего имени: выгружает отчёт, к которому у вашей роли есть доступ, или пишет заметки к занятиям. Как получить ключ, написано на странице API и ключи доступа; как им пользоваться и чем он отличается от OAuth — на странице Аутентификация: ключи API и OAuth.

Формат ошибок

Любая ошибка API — один и тот же объект:

json
{
  "error": {
    "code": "AUTH_REQUIRED",
    "message": "Нужно войти: передайте заголовок Authorization с Bearer-токеном или заголовок X-Api-Key.",
    "requestId": "e47fc5d6-a210-49f2-b480-1384633d1d9f"
  }
}
  • code — машинный код, на него и опирайтесь. Он не меняется от языка.
  • message — объяснение для человека на языке из заголовка Accept-Language (ru, en или zh; по умолчанию русский). Текст может меняться — не разбирайте его.
  • requestId — номер запроса; тот же номер приходит в заголовке X-Request-Id. Назовите его, когда пишете о проблеме.
  • details — бывает у ошибок проверки (VALIDATION_ERROR): details.issues — список полей и что с ними не так.

Самые частые коды:

HTTPcodeЧто значит
400VALIDATION_ERROR, BAD_REQUESTНеверный параметр или тело запроса
401AUTH_REQUIREDМетод требует входа, а ни ключа, ни токена нет
401UNAUTHORIZEDКлюч неверный, отозван или просрочен
401ACCESS_TOKEN_INVALIDBearer-токен недействителен или истёк
403FORBIDDENНе хватает прав; в сообщении — каких именно
403SESSION_REQUIREDМетод только для человека в приложении, ключом его не вызвать
404NOT_FOUND, ROUTE_NOT_FOUNDНет такой записи или такого адреса
429RATE_LIMITEDСлишком много запросов, подождите
500INTERNAL_ERRORОшибка на нашей стороне

Подробнее про 403 — на странице Права доступа (RBAC). Протокольные адреса OAuth (/oauth/token, /oauth/userinfo и другие) отвечают по стандарту OAuth: { "error": "invalid_grant", "error_description": "…" }.

Посмотреть ошибку целиком — запросить без ключа метод, который требует входа:

// /auth/me needs a credential: without one the answer shows the error format.
const API = process.env.VISH_API ?? 'https://d1.vish-app.ru/api/v1'

const response = await fetch(`${API}/auth/me`, { headers: { 'Accept-Language': 'en' } })
const body = await response.json()

if (response.status !== 401 || body.error?.code !== 'AUTH_REQUIRED' || !body.error.requestId) {
	throw new Error(`unexpected answer: ${response.status} ${JSON.stringify(body)}`)
}
console.log(body.error.code, '-', body.error.message)
console.log('requestId:', body.error.requestId)

Ограничение частоты запросов

  • Общий лимит — 300 запросов в минуту на вошедшего человека или, без входа, на IP-адрес.
  • У каждого ключа — свой лимит, по умолчанию 3000 запросов в минуту. Выдуманный ключ лимит не увеличивает: такие запросы считаются по адресу.
  • У тяжёлых методов лимиты свои и строже: календарная лента — 60 в минуту, сводки за период (загруженность, отчёты) и обмен кода OAuth на токен — 30 в минуту, PDF — 10 в минуту.
  • Превышение — ответ 429 с error.code RATE_LIMITED; в сообщении сказано, через сколько секунд повторить. На production ответы несут заголовки RateLimit-Limit, RateLimit-Remaining и RateLimit-Reset, по ним можно притормозить заранее (на d1 23 октября 2026 года их не было).

Версии API

Все адреса начинаются с /api/v1. Внутри v1 API меняется только с сохранением совместимости: добавляются методы, параметры и поля ответов. Если что-то придётся изменить несовместимо, это будет новая версия по новому адресу, а о планах заранее напишем на странице Изменения API.

Что дальше

Проверено: 2026-10, PWA aa337c45, platform bff65fce.