QuizVideo API
REST API для платформы видео-квизов: создавайте квизы, где каждый вопрос начинается с видеофрагмента, а ответ собирается после его просмотра.
https://api.quizvideo.example/v1
Как это работает
video.url, video.startAt, video.endAt# Аутентификация
Все запросы требуют Bearer-токен в заголовке Authorization. Токены создаются в личном кабинете и бывают двух типов: server (полный доступ) и playback (только чтение вопросов и отправка ответов, выдаётся на одну сессию).
curl https://api.quizvideo.example/v1/quizzes \
-H "Authorization: Bearer qv_live_9f2K..."
session_id и истекают через 2 часа. Никогда не передавайте server-токен в клиентское приложение.# Быстрый старт
Минимальный сценарий: создать квиз из одного видео-вопроса и получить его обратно.
{
"title": "Квиз по истории кино",
"passingScore": 70,
"questions": [
{
"text": "Какой фильм показан в этом фрагменте?",
"points": 10,
"video": {
"url": "https://cdn.quizvideo.example/v/hitchcock.mp4",
"startAt": 12.5,
"endAt": 24.0
},
"answers": [
{ "text": "Головокружение", "isCorrect": true },
{ "text": "Психо", "isCorrect": false },
{ "text": "Окно во двор", "isCorrect": false }
]
}
]
}
const res = await fetch("https://api.quizvideo.example/v1/sessions/sg_4a1/answers", {
method: "POST",
headers: {
"Authorization": "Bearer qv_play_8xK...",
"Content-Type": "application/json"
},
body: JSON.stringify({
questionId: "q_77e",
answerId: "a_0b2",
watchedMs: 11480
})
});
const result = await res.json();
console.log(result.correct, result.score); // true, 10
watchedMs не фикция: сервер сверяет его с длительностью фрагмента и помечает ответ как FLAGGED, если видео было пропущено (см. коды ошибок).# Видео-вопросы
Ключевая сущность API. Каждый вопрос содержит объект video — фрагмент, который игрок обязан посмотреть перед ответом.
| Поле | Тип | Описание |
|---|---|---|
video.url | string, required | Ссылка на mp4 или HLS-манифест. Рекомендуем макс. 1080p / 10 Мбит/с. |
video.startAt | float, required | Начало фрагмента в секундах от начала файла. |
video.endAt | float, required | Конец фрагмента. Должен быть больше startAt, минимум 1.0 сек. |
video.muted | bool, default false | Играть фрагмент без звука (например, для «угадай фильм по кадру»). |
video.posterUrl | string, optional | Превью-кадр, показывается до начала воспроизведения. |
video.showQuestionAt | float, optional | Момент внутри фрагмента, когда текст вопроса появляется на экране. По умолчанию — после конца фрагмента. |
timeLimit вопроса (сек) стартует после того, как плеер сообщил событие video.ended.Типы вопросов
| Тип | Как работает с видео |
|---|---|
single_choice | Варианты показываются после фрагмента, выбирается один ответ. |
multiple_choice | Несколько верных вариантов, очки — пропорционально. |
text | Свободный ввод, сервер нормализует регистр и пробелы; опционально fuzzy-match (порог textMatchThreshold). |
order | Расставить события из видео в хронологическом порядке. |
buzz | Можно ответить до конца фрагмента: чем раньше — тем больше очков. |
# Эндпоинты
GET /quizzes Список квизов
Возвращает пагинированный список квизов текущего пользователя.
| Параметр | Тип | Описание |
|---|---|---|
limit | int, optional | 1–100, по умолчанию 20. |
cursor | string, optional | Курсор пагинации из ответа. |
hasVideo | bool, optional | Фильтр: только квизы с видео-вопросами. |
{
"data": [
{
"id": "qz_9c1",
"title": "Квиз по истории кино",
"questionCount": 5,
"videoSeconds": 86.5,
"createdAt": "2026-10-21T09:30:00Z"
}
],
"nextCursor": "cur_x9K2"
}
GET /quizzes/{id} Квиз с вопросами
Полная структура квиза, включая вопросы и объекты video. Поле isCorrect в ответах присутствует только для server-токена.
{
"id": "qz_9c1",
"title": "Квиз по истории кино",
"passingScore": 70,
"questions": [
{
"id": "q_77e",
"type": "single_choice",
"text": "Какой фильм показан в этом фрагменте?",
"points": 10,
"timeLimit": 20,
"video": {
"url": "https://cdn.quizvideo.example/v/hitchcock.mp4",
"startAt": 12.5,
"endAt": 24.0,
"muted": false
},
"answers": [
{ "id": "a_0b2", "text": "Головокружение", "isCorrect": true },
{ "id": "a_1c3", "text": "Психо", "isCorrect": false }
]
}
]
}
POST /quizzes Создать квиз
Создаёт квиз. Видеофайлы нужно предварительно загрузить через POST /uploads и указать полученные URL — прямые ссылки на внешние CDN отклоняются.
processing; проверьте video.status через вебхук quiz.video.ready.{
"id": "qz_9c1",
"status": "processing",
"questions": [
{ "id": "q_77e", "video": { "status": "transcoding" } }
]
}
POST /quizzes/{id}/sessions Начать сессию
Создаёт игровую сессию и возвращает playback-токен для плеера.
{
"sessionId": "sg_4a1",
"playbackToken": "qv_play_8xK...",
"expiresAt": "2026-10-24T18:59:00Z",
"firstQuestion": "q_77e"
}
POST /sessions/{id}/answers Отправить ответ
Принимает ответ на вопрос. Для типа buzz поле answeredAtMs (позиция в фрагменте) влияет на очки.
| Поле | Тип | Описание |
|---|---|---|
questionId | string, required | ID вопроса. |
answerId | string | Для choice-вопросов. |
text | string | Для типа text. |
watchedMs | int, required | Сколько миллисекунд фрагмента реально просмотрено. |
answeredAtMs | int, optional | Только для buzz: позиция в видео, когда дан ответ. |
{
"correct": true,
"score": 10,
"totalScore": 34,
"nextQuestion": "q_88f"
}
DELETE /quizzes/{id} Удалить квиз
Мягкое удаление: квиз скрывается из списка, видеофайлы удаляются из CDN через 24 часа. Возвращает 204 No Content.
# Модели данных
Quiz
| Поле | Тип | Описание |
|---|---|---|
id | string | Уникальный идентификатор, префикс qz_. |
title | string | Название, 1–120 символов. |
passingScore | int | Проходной балл, % от максимума. |
status | string | processing | published | archived. |
questions | Question[] | 1–50 вопросов. |
Question
| Поле | Тип | Описание |
|---|---|---|
id | string | Префикс q_. |
type | string | single_choice | multiple_choice | text | order | buzz. |
video | Video, required | Видеофрагмент вопроса (см. раздел «Видео-вопросы»). |
answers | Answer[] | 2–6 вариантов для choice-типов. |
timeLimit | int | Секунды на ответ после конца фрагмента, 5–120. |
points | int | Баллы за верный ответ, по умолчанию 10. |
# Коды ошибок
API использует стандартные HTTP-статусы. Тело ошибки всегда одного формата:
{
"error": {
"code": "VIDEO_FRAGMENT_INVALID",
"message": "video.endAt must be greater than video.startAt",
"requestId": "req_hK29f"
}
}
| Статус | Код | Причина |
|---|---|---|
| 400 | VIDEO_FRAGMENT_INVALID | endAt ≤ startAt, фрагмент короче 1 сек или выходит за длину файла. |
| 401 | UNAUTHORIZED | Токен отсутствует, просрочен или не подходит по типу. |
| 403 | QUIZ_NOT_PUBLISHED | Попытались играть неопубликованный квиз. |
| 404 | QUIZ_NOT_FOUND | Квиз не существует или удалён. |
| 409 | VIDEO_NOT_WATCHED | watchedMs меньше длительности фрагмента — ответ отклонён. |
| 422 | QUESTION_TIMEOUT | Ответ отправлен позже timeLimit. |
| 429 | RATE_LIMITED | Больше 100 запросов в минуту. |
| 500 | INTERNAL | Ошибка на стороне сервера, повторите с экспоненциальной задержкой. |
# Лимиты
| Ограничение | Значение |
|---|---|
| Длина видеофрагмента | 1 сек – 5 мин |
| Размер видеофайла | до 2 ГБ |
| Форматы | mp4 (H.264/AAC), HLS |
| Вопросов в квизе | 1–50 |
| Rate limit | 100 req/мин на токен |
| Хранение playback-токена | 2 часа |
© 2026 QuizVideo. Вопросы и предложения — api@quizvideo.example