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

# Quickstart

> Generate your first video with the CreatOK API.

This guide submits a 4-second 480p video with `seedance-2-mini`, polls the job, and downloads the result. Check the [pricing page](https://www.creatok.ai/app/api-platform/pricing) for the current rate.

## Prerequisites

* A CreatOK workspace with the API wallet enabled and a positive balance. Contact [support@creatok.ai](mailto:support@creatok.ai) to enable the wallet and top up.
* An organization API key that starts with `cok_`.

<Steps>
  <Step title="Create an API key">
    Open **API Platform → API Keys** in the [API console](https://www.creatok.ai/app/api-platform/api-keys) and create a key. The full key is shown only once, so store it in your secret manager.

    ```bash theme={null}
    export CREATOK_API_KEY="cok_..."
    ```
  </Step>

  <Step title="Check your balance">
    ```bash theme={null}
    curl https://api.creatok.ai/v1/account \
      -H "Authorization: Bearer $CREATOK_API_KEY"
    ```

    ```json theme={null}
    {
      "object": "account",
      "balance": { "amount_usd": "10.000000", "enabled": true },
      "concurrency": { "active": 0, "limit": 3 }
    }
    ```
  </Step>

  <Step title="Submit a generation job">
    Generate a new `Idempotency-Key` for each new job. Reuse it only when you retry the same request.

    ```bash theme={null}
    curl https://api.creatok.ai/v1/videos/generation \
      -H "Authorization: Bearer $CREATOK_API_KEY" \
      -H "Content-Type: application/json" \
      -H "Idempotency-Key: $(uuidgen)" \
      -d '{
        "model": "seedance-2-mini",
        "input": {
          "prompt": "A quiet lake at sunrise, gentle camera movement",
          "seconds": 4,
          "definition": "480p",
          "orientation": "16:9"
        },
        "max_cost_usd": "0.10"
      }'
    ```

    The API responds with `202 Accepted` and a job:

    ```json theme={null}
    {
      "id": "job_3f9c2a...",
      "object": "job",
      "capability": "video.generation",
      "model": "seedance-2-mini",
      "status": "queued",
      "output": { "files": [] },
      "cost": { "amount_usd": "0.076000", "refunded_usd": "0.000000" },
      "error": null,
      "created_at": "2026-10-19T08:00:00.000Z",
      "completed_at": null,
      "expires_at": null
    }
    ```
  </Step>

  <Step title="Poll the job">
    While the job is `queued` or `running`, the response includes a `Retry-After` header. Wait that many seconds before the next request.

    ```bash theme={null}
    curl https://api.creatok.ai/v1/jobs/job_3f9c2a... \
      -H "Authorization: Bearer $CREATOK_API_KEY"
    ```
  </Step>

  <Step title="Download the video">
    When `status` is `succeeded`, download each URL in `output.files`.

    ```json theme={null}
    {
      "status": "succeeded",
      "output": { "files": [{ "type": "video", "url": "https://..." }] },
      "expires_at": "2026-10-21T08:03:00.000Z"
    }
    ```

    <Warning>
      Output URLs expire after about one hour. Fetch the job again for a fresh URL. Outputs are deleted 48 hours after the job completes, so copy them to your own storage.
    </Warning>
  </Step>
</Steps>

## Complete example

```javascript Node.js theme={null}
import { randomUUID } from "node:crypto";
import { writeFile } from "node:fs/promises";

const baseUrl = "https://api.creatok.ai/v1";
const headers = { Authorization: `Bearer ${process.env.CREATOK_API_KEY}` };

async function call(path, init = {}) {
  const res = await fetch(baseUrl + path, { ...init, headers: { ...headers, ...init.headers } });
  const body = await res.json();
  if (!res.ok) throw new Error(`${body.error.code}: ${body.error.message} (${body.error.request_id})`);
  return { body, retryAfter: Number(res.headers.get("retry-after")) || 10 };
}

let { body: job, retryAfter } = await call("/videos/generation", {
  method: "POST",
  headers: { "Content-Type": "application/json", "Idempotency-Key": randomUUID() },
  body: JSON.stringify({
    model: "seedance-2-mini",
    input: { prompt: "A quiet lake at sunrise", seconds: 4, definition: "480p", orientation: "16:9" },
    max_cost_usd: "0.10",
  }),
});

while (job.status === "queued" || job.status === "running") {
  await new Promise((resolve) => setTimeout(resolve, retryAfter * 1000));
  ({ body: job, retryAfter } = await call(`/jobs/${job.id}`));
}

if (job.status !== "succeeded") throw new Error(`Job ${job.status}: ${job.error?.code}`);

const video = await fetch(job.output.files[0].url);
await writeFile("output.mp4", Buffer.from(await video.arrayBuffer()));
```

## Next steps

<CardGroup cols={2}>
  <Card title="Models" icon="film" href="/guides/video-models">
    Choose a model, resolution, and duration.
  </Card>

  <Card title="Errors" icon="triangle-exclamation" href="/guides/errors">
    Handle HTTP errors and failed jobs.
  </Card>
</CardGroup>


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