> ## Documentation Index
> Fetch the complete documentation index at: https://docs.hooked.so/llms.txt
> Use this file to discover all available pages before exploring further.

# Quiz Video Example

> Create trivia quiz videos with narrated questions and a timed reveal

## Overview

A quiz video asks a series of multiple-choice questions. For each one a voice reads the question, the answer options appear, the viewer gets a few seconds to answer, and the correct option lights up. A title stays at the top for the whole video, and an outro closes it.

You send the final list of questions: nothing is generated after the request, so what you send is what the video shows. Every request needs `questions` (2 to 10) and `voiceId` (from `GET /v1/voice/list`).

Each question is `{ question, options, correctIndex }`:

* `question`: what the voice reads (it is also shown as the question's caption);
* `options`: 2 to 4 answers;
* `correctIndex`: the position of the right answer in `options`, starting at 0. An index past the end of the list answers `400`.

## Quick Example

```javascript theme={null}
const response = await fetch('https://api.hooked.so/v1/project/create/quiz-video', {
  method: 'POST',
  headers: {
    'x-api-key': process.env.HOOKED_API_KEY,
    'Content-Type': 'application/json'
  },
  body: JSON.stringify({
    title: 'Guess the Capital',
    questions: [
      {
        question: 'What is the capital of Australia?',
        options: ['Sydney', 'Melbourne', 'Canberra', 'Perth'],
        correctIndex: 2
      },
      {
        question: 'What is the capital of Canada?',
        options: ['Toronto', 'Ottawa', 'Vancouver'],
        correctIndex: 1
      },
      {
        question: 'What is the capital of Brazil?',
        options: ['Rio de Janeiro', 'Brasilia'],
        correctIndex: 1
      }
    ],
    voiceId: '1000',
    webhook: 'https://yoursite.com/webhook?token=YOUR_SECRET'
  })
});

const data = await response.json();
console.log('Project ID:', data.data.projectId);
```

Without `mediaType` the quiz plays over gameplay footage (`subway-s` / `subway-s-1`). The create call answers with the `projectId`; poll `GET /v1/project/{projectId}` or pass a `webhook` to get the finished video.

## Timing, Outro and Style

```javascript theme={null}
const createStyledQuiz = async () => {
  const response = await fetch('https://api.hooked.so/v1/project/create/quiz-video', {
    method: 'POST',
    headers: {
      'x-api-key': process.env.HOOKED_API_KEY,
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      name: 'Science Quiz #4',
      title: 'Only 1% Get All 3 Right',
      questions: [
        {
          question: 'Which planet has the most moons?',
          options: ['Jupiter', 'Saturn', 'Uranus', 'Neptune'],
          correctIndex: 1
        },
        {
          question: 'What is the hardest natural substance on Earth?',
          options: ['Quartz', 'Diamond', 'Titanium', 'Granite'],
          correctIndex: 1
        },
        {
          question: 'How many bones are in the adult human body?',
          options: ['186', '206', '226', '246'],
          correctIndex: 1
        }
      ],
      voiceId: '1000',
      audio: {
        speed: 1.05,
        stability: 0.5,
        similarityBoost: 0.75
      },
      answerSeconds: 4,
      revealSeconds: 1.5,
      showOutro: true,
      outroText: 'How many did you get? Tell us in the comments!',
      optionsStyle: {
        optionBackgroundColor: '#1F2937',
        optionTextColor: '#FFFFFF',
        correctBackgroundColor: '#16A34A',
        showLetters: true
      },
      mediaType: 'gameplay',
      gameplaySettings: {
        selectedGame: 'minecraft',
        selectedVideo: 'minecraft-2'
      },
      aspectRatio: 'ratio_9_16',
      musicId: '1',
      webhook: 'https://yoursite.com/webhook?token=YOUR_SECRET',
      metadata: { series: 'science-quiz' }
    })
  });

  return await response.json();
};
```

## Parameters

| Parameter | Type | Required | Description |
| - | - | - | - |
| `questions` | object\[] | Yes | 2 to 10 questions: `{ question, options, correctIndex }` |
| `voiceId` | string | Yes | Narrator voice from `/v1/voice/list` |
| `title` | string | No | Shown at the top for the whole video (max 120 characters) |
| `audio` | object | No | Narrator voice settings: `speed`, `stability`, `similarityBoost` |
| `answerSeconds` | number | No | Seconds the viewer gets to answer, 1 to 15. Default 5 |
| `revealSeconds` | number | No | Seconds the correct answer stays lit, 0.5 to 6. Default 2 |
| `showOutro` | boolean | No | End on an outro text. Default `true` |
| `outroText` | string | No | With the outro: its text (max 160 characters). Default "Great job! Share your score in the comments!" |
| `optionsStyle` | object | No | Colors and font of the answer rows (see below) |
| `mediaType` | string | No | Background: `gameplay` (default), `ai-images`, `ai-videos` or `media` |
| `gameplaySettings` | object | No | `gameplay`: `{ selectedGame, selectedVideo }`. Default `subway-s` / `subway-s-1` |
| `presetSettings` | object | No | `ai-images` and `ai-videos`: `preset` (default `realistic`), `aiModel` (a model of the wrong kind answers `400`); for `ai-videos` also `quality` (`base`, `pro` or `ultra`) and `isContinuous` (default `true`) |
| `media` | string\[] | `media` only | Library media IDs (max 50) |
| `aspectRatio` | string | No | `ratio_9_16` (default), `ratio_16_9` or `ratio_1_1` |
| `caption` | object | No | `{ disabled: true }` hides the question's caption. The quiz draws its own layout, so only hiding it changes the video |
| `content` | object | No | `{ brandingLogo: { enabled, url, position, size } }`: your logo over the video |
| `musicId` | string | No | Background music ID from `/v1/music/list` |
| `name` | string | No | Project name (max 100 characters) |
| `webhook` | string | No | HTTPS URL called when the video is ready or the project fails |
| `metadata` | object | No | Your own data (max 5KB), sent back in the webhook |

Fields of `optionsStyle`, all optional: `fontFamily`, `optionBackgroundColor`, `optionTextColor`, `correctBackgroundColor`, `showLetters` (A, B, C, D before each answer), `letterBackgroundColor`, `letterTextColor`, `textShadow`.

Gameplay clips: `minecraft-1` to `minecraft-9`, `subway-s-1` to `subway-s-11`, `temple-run-1` to `temple-run-8`, `gta-1` to `gta-12`, `fortnite-1` to `fortnite-5`, `roblox-1`, `free-fire-1` (the game is the part before the number). To use your own footage, send `selectedGame: 'custom'` and a video ID from your library as `selectedVideo`.

<Note>
  Managed teams are charged an estimate made from the narration and the media the background needs, when the project is created; it is refunded if the project fails.

  Teams in bring-your-own-keys mode are not charged credits for generation, but need their own OpenRouter and ElevenLabs keys in Settings → AI keys, plus Gemini when the AI video model is Omni Flash. Without them the call answers `402` with `code: "missing_credentials"` and the `missingProviders` list, before anything is created or charged. To retry a create call after a timeout or 5xx, send it with an [`Idempotency-Key`](/guides/idempotency): the same key never creates or charges twice.
</Note>

## Tips for Quiz Videos

<Tip>**Hook with the title**: "Only 1% get all 3 right" gives viewers a reason to stay</Tip>
<Tip>**Keep questions short**: the voice reads every question, so short ones keep the pace up</Tip>
<Tip>**Three or four options**: enough to make the viewer think, few enough to read in time</Tip>
<Tip>**Ask for the score**: an outro that asks for comments drives engagement</Tip>

## Use Cases

* **Trivia channels**: Geography, science, movies, sports
* **Education**: Quick review quizzes for a lesson
* **Brand engagement**: Questions about your product or industry
* **Community challenges**: Series of quizzes with increasing difficulty

## Handling the Webhook Response

Webhooks are signed: check the `Hooked-Signature` header as shown in [Webhooks](/guides/webhooks#verify-the-signature).

```javascript theme={null}
// Express.js webhook handler
app.post('/webhook', (req, res) => {
  if (req.query.token !== process.env.HOOKED_WEBHOOK_TOKEN) return res.sendStatus(401);

  const { status, message, data } = req.body;
  const { videoId, projectId, url, metadata } = data;

  if (status === 'COMPLETED') {
    console.log('Quiz completed:', projectId, videoId);
    console.log('Download URL:', url);
    console.log('Series:', metadata?.series);
  } else if (status === 'FAILED') {
    // videoId is null when the project failed before it rendered
    console.error(videoId === null ? 'Project failed:' : 'Render failed:', message);
  }

  res.status(200).send('OK');
});
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.