Важно: после запроса одноразового кода на вашу почту придёт письмо. Оно может попасть в папку «Спам». Проверьте «Спам», найдите письмо от api@mgkeit.space и нажмите «Не спам», чтобы получать письма дальше.
Для разработчиков
Как начать, авторизация, лимиты и подробные описания методов с примерами.
Базовый URL https://api.mgkeit.space, префикс /api/v1.
Начало работы
- Запросите одноразовый код при помощи метода POST /auth/request-otp (6 цифр, действует 10 минут).
 - Код нужен для получения токена при помощи метода POST /auth/verify-otp - в ответ вернётся строка вида mgk_live_....
 - При использование API передавайте заголовок Authorization: Bearer <token> или X-API-Key: <token>.
 
Аутентификация
| Тело | Описание | 
|---|---|
| Заголовок | 
                      Authorization: Bearer mgk_live_...
                        или
                        X-API-Key: mgk_live_...
                       | 
                  
| Scopes | read:schedules | 
| Формат ошибок | {"error":{"code","message","details","request_id"}} | 
cURL - при помощи Authorization: Bearer
curl -s "https://api.mgkeit.space/api/v1/auth/me" \
  -H "Authorization: Bearer mgk_live_..."
                  cURL - при помощи X-API-Key
curl -s "https://api.mgkeit.space/api/v1/auth/me" \
  -H "X-API-Key: mgk_live_..."
                  Лимиты и кэш
- С ключом: 100/мин
 - При 
429вернётся заголовокRetry-After /buildings,/groups,/timetable,/replacementsотдаютETagи поддерживаютIf-None-Match
Формат и типы ошибок
{
  "error": {
    "code": "invalid_param | rate_limited | "401" | "404" | "500"",
    "message": "Текст ошибки",
    "details": { подробная ошибка },
    "request_id": "94062d0d..."
  }
}
              | HTTP | Error Code | Когда | 
|---|---|---|
| 400 | "400" | Неверный/просроченный OTP в /auth/verify-otp | 
| 401 | "401" | Недействительный токен | 
| 404 | "404" | Ресурс не найден | 
| 422 | invalid_param | Ошибка валидации | 
| 429 | rate_limited | Превышен лимит | 
| 500 | "500" | Внутренняя ошибка | 
/api/v1/auth/request-otp
              без авторизации
            Отправляет одноразовый код (6 цифр) на указанный Email. Код действует 10 минут.
| Ограничения | Описание | 
|---|---|
| Лимит по ключу | 5 запросов/минуту | 
| Антиспам на адрес | не чаще 1 запроса/мин. на один Email | 
Тело запроса
{ "email": "you@example.com" }
              Ответ (200)
{ "status": "ok" }
                  Ошибки
- 422 - некорректный Email.
 - 429 - частые запросы (общее 5/мин или чаще 1/мин на один адрес).
 - 500 - внутренняя ошибка.
 
curl -s -X POST "https://api.mgkeit.space/api/v1/auth/request-otp" \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com"}'
                import requests
r = requests.post('https://api.mgkeit.space/api/v1/auth/request-otp', json={'email':'you@example.com'})
print(r.json())
                /api/v1/auth/verify-otp
              без авторизации
            
              Проверяет OTP и создаёт API-ключ. Возвращает полный токен с префиксом mgk_live_.
            
| Ограничения | Описание | 
|---|---|
| Лимит | 10 запросов/час | 
| Срок действия OTP | 10 минут | 
Тело запроса
{ "email":"you@example.com", "code":"123456" }
              Ответ (200)
{
  "token": "mgk_live_xxx",
  "token_prefix": "mgk_live_",
  "created_at": "2025-09-07",
  "scopes": ["read:schedules"]
}
                  Ошибки
- 400 - неверный/просроченный код.
 - 422 - ошибки валидации тела.
 - 429 - превышен лимит (10/час).
 
curl -s -X POST "https://api.mgkeit.space/api/v1/auth/verify-otp" \
  -H "Content-Type: application/json" \
  -d '{"email":"you@example.com","code":"123456"}'
                import requests
r = requests.post('https://api.mgkeit.space/api/v1/auth/verify-otp', json={'email':'you@example.com','code':'123456'})
print(r.json())
                /api/v1/auth/me
              без авторизации
            Возвращает информацию о текущем API-ключе (владельце и параметрах лимитов).
| Ограничения | Описание | 
|---|---|
| Лимит | Индивидуальный для ключа (обычно 100/мин). | 
Тело запроса
{ "TOKEN": "mgk_live_..." }
              Ответ (200)
{
  "_id": "XXXXXXXXXXXXXXXXXXXXXXX",
  "email": "you@example.com",
  "active": true,
  "scopes": ["read:schedules"],
  "ratelimit": "100/minute",
  "created_at": "2025-09-09T10:00:00+00:00",
  "last_used_at": "2025-09-09T19:05:00+00:00"
}
                  Ошибки
- 422 - некорректный Email.
 - 429 - частые запросы (общее 5/мин или чаще 1/мин на один адрес).
 - 500 - внутренняя ошибка.
 
curl -s -X POST "https://api.mgkeit.space/api/v1/auth/me" \
  -H "Authorization: Bearer mgk_live_xxx" | jq
                import requests
r = requests.post("https://api.mgkeit.space/api/v1/auth/me", headers={"Authorization": "Bearer mgk_live_xxx"})
print(r.json())
                /api/v1/buildings
              Bearer
            
              Возвращает список всех корпусов.
              Метод поддерживает кэширование по ETag.
            
- Аутентификация при помощи заголовока 
Authorization: Bearer mgk_live_... - Кэш с использованием 
ETagиз ответа. Передавайте его вIf-None-Match- при отсутствии изменений сервер вернёт304 Not Modified. 
| Кэш | Заголовки | 
|---|---|
| ETag + 304 | 
                      ETag
                        ,
                        Cache-Control: public, max-age=60
                        ,
                        If-None-Match
                       | 
                  
cURL
BASE="https://api.mgkeit.space"
TOKEN="mgk_live_xxx"
# Простой запрос
curl -i -X POST "$BASE/api/v1/buildings" \
  -H "Authorization: Bearer $TOKEN"
                  # Повторный запрос с кэшем:
# Подставьте тот ETag, который вернул сервер ранее.
ETAG="<ETAG_ИЗ_ПРЕДЫДУЩЕГО_ОТВЕТА>"
curl -i -X POST "$BASE/api/v1/buildings" \
  -H "Authorization: Bearer $TOKEN" \
  -H "If-None-Match: $ETAG"   # -> 304 Not Modified, если список не менялся
                  Ответ (200)
{
  "buildings": [
    "Судостроительная",
    "Коломенская",
    "Академика Миллионщикова",
    "Бирюлёво"
  ]
}
                  Ошибки
- 401 - отсутствует или неверный Bearer-токен.
 - 422 - некорректное тело запроса (валидация JSON).
 - 304 - данные не изменились (при использовании 
If-None-Match). - 429 - превышен лимит запросов.
 
/api/v1/groups
              Bearer
            
              Возвращает список всех групп для выбранного корпуса. Метод поддерживает кэширование по ETag
            
| Тело (JSON) | Тип | Обяз. | По умолч. | Описание | 
|---|---|---|---|---|
building | 
                    string | да | - | Название корпуса. Рекомендуем получать из /api/v1/buildings. | 
                  
limit | 
                    int [1-500] | нет | 100 | Размер страницы. | 
offset | 
                    int ≥ 0 | нет | 0 | Смещение (для пагинации). | 
| Кэш | Заголовки | 
|---|---|
| ETag + 304 | 
                      ETag
                        ,
                        Cache-Control: public, max-age=60
                        ,
                        If-None-Match
                      
                        При повторном запросе с тем же телом можно отправить  
                    If-None-Match - если данные не изменились, придёт 304 Not Modified.
                       | 
                  
cURL
curl -s -X POST "https://api.mgkeit.space/api/v1/groups" \
  -H "Authorization: Bearer mgk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"building":"Судостроительная","limit":50,"offset":0}' | jq
                  # Следующая страница
curl -s -X POST "https://api.mgkeit.space/api/v1/groups" \
  -H "Authorization: Bearer mgk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"building":"Судостроительная","limit":50,"offset":50}' | jq
                  # Повторный запрос с кэшем
curl -i -X POST "https://api.mgkeit.space/api/v1/groups" \
  -H "Authorization: Bearer mgk_live_xxx" \
  -H "Content-Type: application/json" \
  -H 'If-None-Match: W/"abc123"' \
  -d '{"building":"Судостроительная","limit":50,"offset":0}'   # -> 304 Not Modified
                  Ответ (200)
{
  "building": "Судостроительная",
  "total": 123,
  "limit": 50,
  "offset": 0,
  "groups": ["1КС-1-11-25", "1ОЗИП-1-11-25 (ОЗФ)", "..."]
}
                  Ошибки
- 401 - отсутствует или неверный Bearer-токен.
 - 422 - некорректное тело запроса (валидация JSON).
 - 304 - данные не изменились (при использовании 
If-None-Match). - 429 - превышен лимит запросов.
 
/api/v1/replacements
              Bearer
            Возвращает список замен за указанную дату. Можно дополнительно фильтровать по корпусу и/или группе.
| Тело (JSON) | Тип | Обяз. | По умолч. | Описание | 
|---|---|---|---|---|
date | 
                    string (YYYY-MM-DD) | да | - | Дата замен в формате ISO, например 2025-09-09. Часовой пояс - Europe/Moscow. | 
                  
building | 
                    string | нет | - | Фильтр по корпусу. Если не указан - вернутся замены по всем корпусам за дату. | 
group | 
                    string | нет | - | Фильтр по группе. | 
| Кэш | Заголовки | 
|---|---|
| ETag + 304 | 
                      ETag
                        ,
                        Cache-Control: public, max-age=60
                        ,
                        If-None-Match
                      
                        При повторном запросе с тем же телом можно отправить  
                    If-None-Match -
                        если данные не изменились, придёт 304 Not Modified.
                       | 
                  
cURL
# Все замены по дате
curl -s -X POST "https://api.mgkeit.space/api/v1/replacements" \
  -H "Authorization: Bearer mgk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"date":"2025-09-09"}' | jq
                  # Фильтр по корпусу
curl -s -X POST "https://api.mgkeit.space/api/v1/replacements" \
  -H "Authorization: Bearer mgk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"date":"2025-09-09","building":"Академика Миллионщикова"}' | jq
                  # Фильтр по группе
curl -s -X POST "https://api.mgkeit.space/api/v1/replacements" \
  -H "Authorization: Bearer mgk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"date":"2025-09-09","group":"1ИП-3-25"}' | jq
                  # Повторный запрос с кэшем
curl -i -X POST "https://api.mgkeit.space/api/v1/replacements" \
  -H "Authorization: Bearer mgk_live_xxx" \
  -H "Content-Type: application/json" \
  -H 'If-None-Match: W/"abc123"' \
  -d '{"date":"2025-09-09"}'   # -> 304 Not Modified
                  Ответ (200)
{
  "meta": {
    "version": "1.0",
    "date": "2025-09-09",
    "building": "Академика Миллионщикова",
    "count": 3
  },
  "items": [
    {
      "group": "2ИП-4-24",
      "lessons": [3, 4],
      "teacher_from": "Геворгян А.А.",
      "teacher_to": "Ахмерова Н.Д.",
      "room_schedule": "411",
      "room_replace": null
    },
    {
      "group": "1РКИ-3-25",
      "lessons": [3],
      "teacher_from": "Вакансия",
      "teacher_to": "Мызников В.И.",
      "room_schedule": "320",
      "room_replace": "102"
    },
    {
      "group": "1ИП-6-25",
      "lessons": [5, 6],
      "teacher_from": "Маликова А.Р.",
      "teacher_to": "Горбунов О.В.",
      "room_schedule": "307",
      "room_replace": null
    }
  ]
}
                  Примечания
- Совмещение фильтров. Если указаны и 
buildingиgroup- применяются оба фильтра. - Нумерация занятий. Поле 
lessonsсодержит номера занятий по дню. - Кэширование. Ответ кэшируется заголовками 
ETag/Cache-Control; можно использоватьIf-None-Matchдля экономии трафика. 
Ошибки
- 401 - отсутствует или неверный Bearer-токен.
 - 422 - некорректное тело запроса (например, опечатка в ключе 
date). - 304 - данные не изменились (при использовании 
If-None-Match). - 429 - превышен лимит запросов.
 
/api/v1/timetable
              Bearer
            
              Возвращает расписание группы на выбранный день или на «рабочие» дни корпуса (если день не указан и для корпуса задано ограничение).
              Парные пары уже объединены и имеют итоговое время в полях start/end.
            
| Тело (JSON) | Тип | Обяз. | По умолч. | Описание | 
|---|---|---|---|---|
group | 
                    string | да | - | Название группы, например 1ОЗИП-1-11-25 (ОЗФ) или 1КС-1-11-25. | 
                  
building | 
                    string | нет | - | Название корпуса, например если одинаковые названия групп встречаются в разных корпусах. Если не указан - выбирается лучший матч автоматически. | 
week | 
                    "current"|"even"|"odd" | 
                    нет | "current" | 
                    Выбранная неделя для отдачи. Текущая, чётная, нечётная | 
day | 
                    int (0-5) | нет | - | День недели. 0 - Пн, 1 - Вт, 2 - Ср, 3 - Чт, 4 - Пт, 5 - Сб. Если не указан - вернутся только «разрешённые» дни для корпуса. | 
| Кэш | Заголовки | 
|---|---|
| ETag + 304 | 
                      ETag
                        ,
                        Cache-Control: public, max-age=60
                        ,
                        If-None-Match
                      
                        При повторном запросе с тем же телом можно отправить  
                    If-None-Match - если данные не изменились, придёт 304 Not Modified.
                       | 
                  
cURL
# Минимальный запрос (корпус определится автоматически)
curl -s -X POST "https://api.mgkeit.space/api/v1/timetable" \
  -H "Authorization: Bearer mgk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"group":"1ОЗИП-1-11-25 (ОЗФ)"}' | jq
                  # С указанием корпуса, недели и дня (среда)
curl -s -X POST "https://api.mgkeit.space/api/v1/timetable" \
  -H "Authorization: Bearer mgk_live_xxx" \
  -H "Content-Type: application/json" \
  -d '{"group":"1ОЗИП-1-11-25 (ОЗФ)","building":"Академика Миллионщикова","week":"odd","day":2}' | jq
                  # Повторный запрос с кэшем
curl -i -X POST "https://api.mgkeit.space/api/v1/timetable" \
  -H "Authorization: Bearer mgk_live_xxx" \
  -H "Content-Type: application/json" \
  -H 'If-None-Match: W/"abc123"' \
  -d '{"group":"1ОЗИП-1-11-25 (ОЗФ)","day":2}'   # -> 304 Not Modified
                  Ответ (200)
{
  "meta": {
    "version": "1.0",
    "generated_at": "2025-09-09T19:04:24.941351+00:00",
    "group": "1ОЗИП-1-11-25 (ОЗФ)",
    "building": "Академика Миллионщикова",
    "week": "even",
    "current_week": "even",
    "day_filter": 2
  },
  "data": [
    {
      "day_index": 2,
      "day_name": "Среда",
      "units": [
        {
          "kind": "pair",
          "number": 1,
          "display_number": 1,
          "start": "15:50",
          "end": "17:20",
          "subject": "ОП.02 Информационные технологии / Адаптивные информационные и коммуникационные технологии",
          "teacher": "Вакансия часы ОЗ",
          "room": "академика Миллионщикова. каб: 321",
          "subgroup": "",
          "source": "base"
        },
        {
          "kind": "pair",
          "number": 2,
          "display_number": 2,
          "start": "17:30",
          "end": "19:00",
          "subject": "ОГСЭ.02 История",
          "teacher": "Вакансия часы ОЗ",
          "room": "академика Миллионщикова. каб: 305",
          "subgroup": "",
          "source": "base"
        }
      ]
    }
  ]
}
                  Как выбирается корпус и день
- Группа. Ищем строгое совпадение с припиской в скобках, затем «база+приписка», затем «база без приписки». Если задан 
building, он учитывается в поиске. - Корпус. Если 
buildingне указан, выбирается документ с непустым корпусом и самой поздней датой обновления. - Дни. Если 
dayне указан, возвращаются только «разрешённые» дни для выбранного корпуса. - Склейка пар. Две соседние одинаковые записи (предмет/преподаватель/аудитория/подгруппа) объединяются в 
kind="pair"с суммарным временем. 
Ошибки
- 401 - отсутствует или неверный Bearer-токен.
 - 422 - некорректное тело запроса (валидация JSON).
 - 304 - данные не изменились (при использовании 
If-None-Match). - 429 - превышен лимит запросов.