TenantAdminCuratorStudent

Записи на курсы

Самостоятельная запись студента на курс, кураторский список и CSV-экспорт записей, массовая запись, снятие с курса, список «мои курсы», отметка о прохождении блока. Все эндпоинты живут под /api/v1/t/* и требуют JWT + заголовок X-Tenant-Subdomain.

POST/api/v1/t/courses/:id/enroll

Записаться на курс

Student JWT

Записывает текущего студента на опубликованный курс. Тело запроса пустое — студент берётся из JWT, передать чужой student_id невозможно. Идемпотентно: при уже активной записи возвращается 200 с существующей строкой.

201 Created — создана новая запись; 200 OK — запись уже существовала или была восстановлена. Курс, входящий в траекторию обучения и ещё не разблокированный для студента, отклоняется с 409 course_locked.

Параметры пути

ПараметрТипОписание
idобяз.uuidID курса.

Пример запроса

cURL
curl -X POST https://api.edumentor.kz/api/v1/t/courses/2b1a.../enroll \
  -H "Authorization: Bearer <token>" \
  -H "X-Tenant-Subdomain: acme"

Пример ответа

200 OK · application/json
{
  "success": true,
  "data": {
    "id": "9c1f...",
    "student_id": "8f3b...",
    "course_id": "2b1a...",
    "enrolled_at": "2026-05-28T10:00:00Z",
    "enrolled_by": null,
    "last_accessed_block_id": null
  }
}

Ошибки

КодerrorКогда
400invalid_course_idID курса в пути не является UUID.
401unauthorizedТокен отсутствует, истёк или недействителен.
403tenant_requiredШкола (тенант) не определена для запроса.
404course_not_foundКурс отсутствует, в черновике или принадлежит другой школе (схлопывание для приватности).
409course_lockedКурс входит в траекторию обучения и ещё не разблокирован для этого студента.
GET/api/v1/t/courses/:id/enrollments

Список записей на курс

AdminCurator JWT право: manage_students

Кураторско-административный список студентов, записанных на курс, с прогрессом, счётчиками по статусам и средним прогрессом. Непривилегированный куратор видит только своих студентов.

Пагинация: page (с 1), limit (по умолчанию 20, ограничен 1..100). Счётчики counts и avg_progress считаются под фильтром q, но игнорируют фильтр status.

Параметры пути

ПараметрТипОписание
idобяз.uuidID курса.

Query-параметры

ПараметрТипОписание
qопц.stringПоиск по имени/email студента.
statusопц.stringФильтр по статусу: active | risk | done | notstarted.
pageопц.integerНомер страницы (с 1). По умолчанию 1.Пример: 1
limitопц.integerРазмер страницы (1..100). По умолчанию 20.Пример: 20

Пример запроса

cURL
curl "https://api.edumentor.kz/api/v1/t/courses/2b1a.../enrollments?page=1&limit=20" \
  -H "Authorization: Bearer <token>" \
  -H "X-Tenant-Subdomain: acme"

Пример ответа

200 OK · application/json
{
  "success": true,
  "data": {
    "enrollments": [
      {
        "enrollment_id": "9c1f...",
        "student_id": "8f3b...",
        "student_email": "student@acme.kz",
        "student_first_name": "Айгерим",
        "student_last_name": "Нурлан",
        "enrolled_at": "2026-05-28T10:00:00Z",
        "enrolled_by": null,
        "blocks_completed": 3,
        "total_blocks": 10,
        "pct": 30,
        "last_accessed_at": "2026-05-28T11:00:00Z",
        "completed_at": null
      }
    ],
    "total": 1,
    "page": 1,
    "limit": 20,
    "counts": { "all": 1, "active": 1, "risk": 0, "done": 0, "notstarted": 0 },
    "avg_progress": 30
  }
}

Ошибки

КодerrorКогда
400invalid_course_idID курса в пути не является UUID.
401unauthorizedТокен отсутствует, истёк или недействителен.
403permission_deniedНет права manage_students (или не определена школа).
404course_not_foundКурс отсутствует, в черновике или принадлежит другой школе.
GET/api/v1/t/courses/:id/enrollments/export.csv

Экспорт записей в CSV

AdminCurator JWT право: manage_students

Выгружает все активные записи на курс в CSV (без пагинации и фильтров — «весь курс»). Та же проверка прав, что и у списка; непривилегированный куратор получает только своих студентов.

Ответ — text/csv; charset=utf-8 с BOM в начале (чтобы Excel на Windows корректно открыл кириллицу). Имя файла отдаётся в Content-Disposition. Заголовки колонок: ФИО, Email, Дата записи, Прогресс %, Завершено блоков, Всего блоков, Статус, Последняя активность. Значения статуса: «активен» | «в зоне риска» | «завершил» | «не начал».

Параметры пути

ПараметрТипОписание
idобяз.uuidID курса.

Пример запроса

cURL
curl "https://api.edumentor.kz/api/v1/t/courses/2b1a.../enrollments/export.csv" \
  -H "Authorization: Bearer <token>" \
  -H "X-Tenant-Subdomain: acme" -o enrollments.csv

Пример ответа

200 OK · application/json
Content-Type: text/csv; charset=utf-8

ФИО,Email,Дата записи,Прогресс %,Завершено блоков,Всего блоков,Статус,Последняя активность
Айгерим Нурлан,student@acme.kz,2026-05-28,30,3,10,активен,2026-05-28 11:00

Ошибки

КодerrorКогда
400invalid_course_idID курса в пути не является UUID.
401unauthorizedТокен отсутствует, истёк или недействителен.
403permission_deniedНет права manage_students.
404course_not_foundКурс отсутствует, в черновике или принадлежит другой школе.
POST/api/v1/t/courses/:id/enroll/bulk

Массовая запись студентов

AdminCurator JWT право: manage_students

Записывает список студентов на курс одним запросом (частичный успех). Каждый необработанный студент попадает в skipped[] с причиной. Для непривилегированного куратора студенты вне его охвата пропускаются с причиной not_in_scope.

Всегда 200, даже если часть пропущена. Причины пропуска: already_enrolled | user_not_found | wrong_tenant | course_not_published. Существует второй массовый эндпоинт POST /api/v1/t/courses/:id/enroll-bulk (через дефис) с правом manage_groups — см. раздел «Группы».

Параметры пути

ПараметрТипОписание
idобяз.uuidID курса.

Тело запроса

ПараметрТипОписание
student_idsобяз.string[]Массив UUID студентов (от 1 до 500).

Пример запроса

cURL
curl -X POST https://api.edumentor.kz/api/v1/t/courses/2b1a.../enroll/bulk \
  -H "Authorization: Bearer <token>" \
  -H "X-Tenant-Subdomain: acme" \
  -H "Content-Type: application/json" \
  -d '{ "student_ids": ["8f3b...", "7a2c..."] }'

Пример ответа

200 OK · application/json
{
  "success": true,
  "data": {
    "enrolled": ["8f3b..."],
    "skipped": [{ "student_id": "7a2c...", "reason": "already_enrolled" }],
    "enrolled_count": 1,
    "skipped_count": 1
  }
}

Ошибки

КодerrorКогда
400invalid_bodyНекорректное тело запроса (нарушены binding-правила).
400student_ids_cap_exceededПревышен лимит количества student_ids.
401unauthorizedТокен отсутствует, истёк или недействителен.
403permission_deniedНет права manage_students.
404course_not_foundКурс отсутствует, в черновике или принадлежит другой школе.
DELETE/api/v1/t/courses/:id/enrollments/:student_id

Снять студента с курса

AdminCurator JWT право: manage_students

Снимает активную запись студента с курса (административное действие). Непривилегированный куратор может снять только своего студента; цель вне охвата схлопывается в 404.

204 No Content при успехе.

Параметры пути

ПараметрТипОписание
idобяз.uuidID курса.
student_idобяз.uuidID студента.

Пример запроса

cURL
curl -X DELETE https://api.edumentor.kz/api/v1/t/courses/2b1a.../enrollments/8f3b... \
  -H "Authorization: Bearer <token>" \
  -H "X-Tenant-Subdomain: acme"

Пример ответа

200 OK · application/json
HTTP/1.1 204 No Content

Ошибки

КодerrorКогда
400invalid_course_idID курса в пути не является UUID.
400invalid_student_idID студента в пути не является UUID.
401unauthorizedТокен отсутствует, истёк или недействителен.
403permission_deniedНет права manage_students.
404enrollment_not_foundАктивная запись не найдена (или вне охвата куратора / другая школа).
GET/api/v1/t/me/courses

Мои курсы

Student JWT

Постраничный список курсов, на которые записан текущий студент, с вычисленным процентом прохождения, указателем на последний открытый блок и временем завершения. Возвращает массив строк StudentCourseListItem.

Курсы с активной записью, но снятые с публикации, всё равно показываются в этом списке. Поле auth_has_access в каждой строке всегда true — каждая строка соответствует курсу, на который студент записан.

Query-параметры

ПараметрТипОписание
limitопц.integerРазмер страницы. По умолчанию 20.Пример: 20
offsetопц.integerСмещение. По умолчанию 0.Пример: 0

Пример запроса

cURL
curl "https://api.edumentor.kz/api/v1/t/me/courses?limit=20&offset=0" \
  -H "Authorization: Bearer <token>" \
  -H "X-Tenant-Subdomain: acme"

Пример ответа

200 OK · application/json
{
  "success": true,
  "data": [
    {
      "course_id": "2b1a...",
      "course_title": "Основы Go",
      "course_status": "published",
      "cover_image_id": "4d2e...",
      "enrollment_id": "9c1f...",
      "enrolled_at": "2026-05-28T10:00:00Z",
      "last_accessed_block_id": "1a1a...",
      "last_accessed_at": "2026-05-28T11:00:00Z",
      "blocks_completed": 3,
      "total_blocks": 10,
      "pct": 30,
      "completed_at": null,
      "auth_has_access": true
    }
  ]
}

Ошибки

КодerrorКогда
401unauthorizedТокен отсутствует, истёк или недействителен.
403tenant_requiredШкола (тенант) не определена для запроса.
GET/api/v1/t/courses/:id/my-completions

Пройденные блоки курса

Student JWT

Возвращает ID всех блоков курса, для которых у текущего студента есть отметка о прохождении. Владелец берётся из JWT — student_id передать нельзя. Используется фронтендом для постоянных галочек «уже пройдено».

Пустой массив block_ids — нормальная ситуация.

Параметры пути

ПараметрТипОписание
idобяз.uuidID курса.

Пример запроса

cURL
curl "https://api.edumentor.kz/api/v1/t/courses/2b1a.../my-completions" \
  -H "Authorization: Bearer <token>" \
  -H "X-Tenant-Subdomain: acme"

Пример ответа

200 OK · application/json
{
  "success": true,
  "data": {
    "block_ids": ["1a1a...", "1b1b..."]
  }
}

Ошибки

КодerrorКогда
400invalid_course_idID курса в пути не является UUID.
401unauthorizedТокен отсутствует, истёк или недействителен.
403tenant_requiredШкола (тенант) не определена для запроса.
404course_not_foundКурс отсутствует, не опубликован, другая школа или нет активной записи (схлопывание).
POST/api/v1/t/blocks/:id/complete

Отметить блок пройденным

Student JWT

Помечает блок курса как пройденный текущим студентом (ручное прохождение текстовых/видео/PDF-блоков). Владелец берётся из JWT — отметить блок за другого студента структурно невозможно. Идемпотентно.

Блоки типа quiz_ref завершаются через прохождение теста, а не этим эндпоинтом (400). Для блока assignment_ref требуется отправленная/проверенная работа, иначе 422 assignment_not_submitted.

Параметры пути

ПараметрТипОписание
idобяз.uuidID блока контента.

Пример запроса

cURL
curl -X POST https://api.edumentor.kz/api/v1/t/blocks/1a1a.../complete \
  -H "Authorization: Bearer <token>" \
  -H "X-Tenant-Subdomain: acme"

Пример ответа

200 OK · application/json
{
  "success": true,
  "data": {
    "id": "5f5f...",
    "student_id": "8f3b...",
    "block_id": "1a1a...",
    "enrollment_id": "9c1f...",
    "source": "manual",
    "completed_at": "2026-05-28T11:30:00Z"
  }
}

Ошибки

КодerrorКогда
400invalid_block_idID блока в пути не является UUID.
400block_type_completed_via_domainБлок типа quiz_ref/assignment_ref завершается через свой домен, а не вручную.
401unauthorizedТокен отсутствует, истёк или недействителен.
403tenant_requiredШкола (тенант) не определена для запроса.
404block_not_foundБлок не в курсе с активной записью (или другая школа) — схлопывание.
422assignment_not_submittedБлок assignment_ref: нет отправленной или проверенной работы.