Помощь · Интеграции

Документация API

Публичные маршруты Latorn для учётных записей, обучения и преподавательских инструментов. Каждый раздел можно читать отдельно.

Здесь описаны только пользовательские и преподавательские интеграции. Служебные операции платформы в публичный справочник не входят.

Справочник API

Курсы, уроки и шаги

Создание структуры курса, копирование материалов, режимы доступа к урокам и загрузка медиафайлов.

Маршруты раздела

Метод Маршрут Доступ Назначение
GET /api/courses Зависит от фильтра Получить доступные курсы или рабочий список преподавателя.
POST /api/courses Преподаватель Создать черновик курса.
GET /api/courses/[id] По доступу к курсу Получить курс по идентификатору или адресу.
PUT /api/courses/[id] Редактирование курса Изменить настройки или опубликовать курс.
DELETE /api/courses/[id] Владелец курса Переместить курс в удалённые.
POST /api/courses/[id]/duplicate Управление курсом Создать независимую копию курса.
PATCH /api/instructor/courses/[id]/content/reorder Редактирование курса Атомарно применить полный порядок модулей, уроков или шагов.
GET /api/sections?courseId=[id] Чтение курса Получить модули курса.
POST /api/sections Редактирование курса Создать модуль.
GET /api/sections/[id] Чтение курса Получить один модуль.
PUT /api/sections/[id] Редактирование курса Изменить или переместить модуль.
DELETE /api/sections/[id] Редактирование курса Удалить модуль.
GET /api/lessons?sectionId=[id] Чтение курса Получить уроки модуля.
POST /api/lessons Редактирование курса Создать урок.
GET /api/lessons/[id] Чтение курса Получить урок.
PUT /api/lessons/[id] Редактирование курса Изменить урок и срок выполнения.
DELETE /api/lessons/[id] Редактирование курса Удалить урок.
POST /api/lessons/[id]/duplicate Редактирование курса Скопировать урок в выбранный модуль.
GET /api/steps?lessonId=[id] Редактирование курса Получить шаги урока для редактора.
POST /api/steps Редактирование курса Создать шаг.
GET /api/steps/[id] Редактирование курса Получить шаг для редактора.
PUT /api/steps/[id] Редактирование курса Изменить шаг или его положение.
DELETE /api/steps/[id] Редактирование курса Удалить шаг.
POST /api/uploads/course-cover Преподаватель Загрузить обложку курса.
POST /api/uploads/lesson-media Преподаватель Загрузить изображение, аудио или WebM для урока.

Иерархия материалов

Курс состоит из модулей, модуль — из уроков, урок — из шагов:

Курс → Модуль → Урок → Шаг

При создании и изменении поддерживаются как прямой JSON, так и именованная оболочка: { "course": { ... } }, { "lesson": { ... } } и аналогичные варианты.

Как менять порядок без конфликтов

Не отправляйте серию PUT /api/lessons/[id] или PUT /api/steps/[id] с разными position: промежуточные позиции могут конфликтовать. Для сортировки используйте один атомарный запрос PATCH /api/instructor/courses/[id]/content/reorder с полным снимком порядка.

Шаги одного урока:

{ "kind": "STEPS", "lessonId": "lesson-id", "orderedStepIds": ["step-2", "step-1"] }

Все уроки курса, включая перенос между модулями:

{
  "kind": "LESSONS",
  "sections": [
    { "sectionId": "section-1", "orderedLessonIds": ["lesson-2"] },
    { "sectionId": "section-2", "orderedLessonIds": ["lesson-1"] }
  ]
}

Модули курса передают и исходный, и новый полный порядок:

{
  "kind": "SECTIONS",
  "expectedSectionIds": ["section-1", "section-2"],
  "orderedSectionIds": ["section-2", "section-1"]
}

Нужен scope CONTENT_WRITE; для PAT курс также должен оставаться в courseIds, а у владельца — актуальное право content:write. Неполный или устаревший снимок возвращает 409 без частичной записи.

Создание курса

Минимальный запрос:

{
  "title": "Основы Python",
  "description": "Практический курс для начинающих",
  "price": 0
}

Новый курс сохраняется черновиком. Перед публикацией сервер строго проверяет структуру и блоки всех шагов.

Режимы доступа к уроку

Поле accessMode принимает:

  • PUBLIC — урок открывается без регистрации;
  • REGISTERED — нужен аккаунт, но покупка не требуется;
  • PAID — нужен доступ к курсу.

Поле isDemo оставлено для совместимости. В новых интеграциях записывайте accessMode.

Типы шагов

Режим PROJECT — многофайловый HTTP-сервис. Профили: project-go-127 (Go), project-python-312 (Python/FastAPI), project-rust-198 (Rust 1.98/Axum/Tokio). Поле project содержит files: [{path, content, editable}], entrypoint (./directory, main:app или фиксированный src/main.rs для Rust), readinessPath, postgres: {enabled, seedSql} и checks. До 12 файлов, 20 000 символов на файл и 80 000 суммарно; относительные ASCII-пути без скрытых файлов и ..; go.mod/go.sum и Cargo.toml/Cargo.lock задаёт платформа, build.rs и переопределения toolchain запрещены. Rust-файлы находятся внутри src/, зависимости уже собраны, Cargo работает offline. Ученик отправляет в code JSON-строку с files: [{path, content}] — ровно все редактируемые файлы. Остальные файлы добавляет сервер.

В PROJECT можно включить redis.enabled; подключение доступно как REDIS_URL. Для самостоятельной HTTP-песочницы задаётся отдельный публичный postgres.playgroundSeedSql: приватный seedSql туда не копируется. Проверки поддерживают faultBefore (NONE, REDIS_STOP, REDIS_START, REDIS_RESTART, POSTGRES_STOP, POSTGRES_START), waitBeforeMs (0–5000, суммарно до 20 секунд) и parallelRequests (1–5 одинаковых запросов). Для зачёта группы должны пройти все ответы; переменные берутся из первого. Redis после перезапуска пустой, PostgreSQL сохраняет данные. Песочница открывается только в кабинете ученика и не меняет оценку; PAT/MCP к сессиям доступа не имеют.

Проверки проекта — до 20 последовательных HTTP-запросов: method, path, body, expectedStatus, expectedBody, bodyMatch (JSON/TEXT/IGNORE), name, points, hidden, learnerFailureMessage, restartBefore, capture: [{name, pointer}]. JSON Pointer сохраняет значение из ответа; следующие запросы используют {{id}} в пути или {"$ref":"id"} в JSON. Тела ограничены 8000 символов, JSON — 24 уровнями и точными конечными числами. База новая на каждый запуск, перезапуск сервиса внутри сценария её сохраняет. После ошибки остальные запросы пропускаются, баллы уже пройденных остаются. Скрытые сценарии не раскрывают сырой HTTP-вывод. Этапы подготовки, сборки и запуска возвращаются отдельно в projectPhases. Нужен настроенный исполнитель проектов.

Go-функции используют режим GO_FUNCTION, язык go, профиль go-127-modal и goFunction: {name: "Sum"}. Ученик пишет функцию в package main, без main(). В testCases поле input — JSON-массив аргументов ([[1,2,3]] для одного среза), output — ожидаемый результат JSON. Несколько возвращаемых значений передаются массивом; error — строкой или null. Порядок ключей объекта не важен, порядок массива и типы значений важны. Большие целые вне точного диапазона JavaScript передавайте строками. До 20 тестов, до 8000 символов на ввод/результат, глубина JSON до 32; лимит одной проверки 1–15 секунд, общий до 60 секунд, память 64–256 МиБ. Доступна стандартная библиотека. Поддерживаются названия тестов, баллы, сообщения и подсказки, описанные ниже. Скрытые данные не входят в программу ученика; проверка результата идёт на сервере. Собственный запуск принимает аргументы без выставления оценки. Этот режим не является запуском произвольных _test.go или многофайлового проекта.

Практика командной строки использует отдельные CODE-режимы. SHELL_SCRIPT (язык bash, профиль modal-devtools-debian-12) запускает ровно bash solution.sh в одноразовом workspace без сети; GIT_FIXTURE проверяет финальное состояние локального репозитория — branch, HEAD message, commit count, clean state, branches и файлы. DOCKERFILE (язык docker, профиль modal-docker-27-vm) собирает и запускает Dockerfile в одноразовой Modal VM без сети. Разрешены только предзагруженные alpine:3.20 и busybox:1.36; host mounts, registries и learner-controlled daemon commands недоступны. Конфигурация хранится в devtools.workspace, devtools.git или devtools.docker и devtools.assertions; полный JSON приведён в docs/API_IMPORT.md. Если MODAL_DEVTOOLS_EXECUTION_URL не настроен или провайдер вернул некорректный ответ, проверка завершается fail closed.

Для структурного сравнения JSON в обычном STDIO также доступно outputComparison: {mode: "JSON"}.

C/C++: режим NATIVE_FUNCTION, профили native-c-17 / native-cpp-20, язык c / cpp. Поле nativeFunction: {header, driver, checkMemory}: открытые объявления и код main(), вызывающий функции или классы ученика; checkMemory по умолчанию true. Оба текста до 20 000 символов; driver обязателен. Ожидаемые ответы — только в testCases, не в driver. До 10 тестов, 8000 символов на ввод/вывод, 1–3 секунды и 64–256 МиБ (по умолчанию 2/256). Доступны баллы, подсказки и outputComparison (по умолчанию TRIM). Clang 14, C17/C++20; отдельный запуск ASan/UBSan выявляет ошибки памяти. Каждый тест изолирован, сравнение — на сервере. Скрытый тест показывает вердикт MEMORY_ERROR, но не диагностический вывод. Запуск на своих данных не создаёт попытку; PAT/MCP к исполнителю доступа не имеют.

Для CODE с режимом STDIO можно задать outputComparison: mode — EXACT (точно, с нормализацией переносов строк), TRIM (без пробелов по краям), TOKENS (без различий в разделяющих пробелах), NUMERIC (числовые значения с абсолютной погрешностью). Для NUMERIC поле tolerance — от 0 до 0.01, по умолчанию 0.000001. Без этой настройки сохраняются прежние правила задания. Настройка доступна через обычные права записи содержания и видна ученику.

В STDIO и PYTHON_TEST_CODE у теста или набора можно указать points — целое число от 1 до 1000, по умолчанию 1. Частичный результат — доля набранных баллов; для полного зачёта нужны все проверки. Поле learnerFailureMessage (до 500 символов) задаёт сообщение при неверном ответе или ошибке, в том числе у скрытого теста. Закрытые данные и технический вывод при этом не раскрываются.

Поле name у теста STDIO или набора Python задаёт необязательное название до 120 символов. Без него показывается «Тест 1», «Тест 2» и так далее. Название меняется прямо в заголовке выбранного теста; название скрытой проверки ученику не передаётся.

В этих режимах поле hints содержит до 10 подсказок: {afterAttempts: 3, text: "Проверьте граничный случай"}. Порог — от 1 до 100 неудачных отправок, текст — от 1 до 2000 символов. Считаются сохранённые неверные решения, ошибки и превышения времени; самостоятельные запуски не учитываются. До открытия текст подсказки не передаётся ученику. Эти поля сохраняются через обычные права записи содержания курса.

Учащийся может запускать собственный Python-код интерактивно: программа сохраняет состояние, принимает строки и показывает вывод до завершения. Для этого требуется подключённый интерактивный исполнитель. Авторские тесты и preCode в собственном запуске не исполняются, оценка и прогресс не меняются. Это отдельная возможность кабинета учащегося, недоступная через PAT/MCP; автору не нужно менять формат задания.

Поддерживаются TEXT, VIDEO, CODE, CHOICE, NUMBER, FREE_TEXT, SORTING, MATCHING и REVIEW. В штатном редакторе тип выбирается при создании. Низкоуровневый PUT /api/steps/[id] также принимает новый type, но вместе с ним обязательно нужно передать новый совместимый block.

Текстовая задача FREE_TEXT принимает многострочный answer.value. Каждый элемент answers — целый допустимый ответ. ignoreCase управляет регистром, trimWhitespace — пробелами по краям, matchSubstring — поиском ответа внутри текста. Для своей проверки задайте pythonChecker с функцией check(reply): результат — True/False, число от 0 до 1 или пара (балл, комментарий). В этом режиме answers пуст, acceptAny и acceptRegex выключены. Код скрыт от ученика, выполняется без сети с лимитом 3 секунды и 128 МБ; комментарий показывается после проверки. Авторский API возвращает код только в рамках прав на содержание курса.

Пример числовой задачи:

{
  "lessonId": "lesson-id",
  "type": "NUMBER",
  "block": {
    "text": "Сколько будет 6 × 7?",
    "answer": 42,
    "tolerance": 0,
    "correctFeedback": "Верно",
    "incorrectFeedback": "Проверьте умножение"
  }
}

Правильные ответы, скрытые тесты и подсказки проверяющему возвращаются только в преподавательских ответах.