Getting started

Quick Start

On this page
  1. Install a client
  2. Get your key
  3. Your first image
  4. Your first video
  5. Wait, then download
  6. What it costs
  7. Where next

Install a client, create your API key, and generate an image and a video. Each example waits for the job and downloads the finished file; choose the language you use.

An image taking shape from a request
An image taking shape from a request

Install a client #

Choose one install; every tab is one command. The examples below use the published packages, and each tab needs only the tool it names. The Python package, nolgia, needs Python 3.10 or later.

shell
npm install @nolgia/sdk
shell
yarn add @nolgia/sdk
shell
pnpm add @nolgia/sdk
shell
bun add @nolgia/sdk
shell
pip install nolgia
shell
uv add nolgia
shell
cargo add nolgia
shell
brew install nolgiainc/nolgia/nolgia
shell
curl -fsSL https://raw.githubusercontent.com/nolgiainc/nolgia-cli/main/install.sh | bash
shell
curl https://api.nolgia.ai/v1/me -H "Authorization: Bearer $NOLGIA_TOKEN"

Get your key #

Create a Personal Access Token at nolgia.ai/settings/api-tokens, copy it once, and set it in your environment; it starts with nol_. The CLI can instead open the browser device flow with nolgia auth login; see Get your API key.

shell
export NOLGIA_TOKEN=nol_...
nolgia auth login

Your first image #

Generate a paper-cut mountain range with flux-3-image and save it as first.png. The curl tab shows each call in turn: submit, wait on the returned id, then download asset.signed_url from the finished job. Every SDK tab downloads the file itself (in Rust, nolgia.download(url, path)), so nothing here needs a package its install tab did not name.

shell
curl -sS https://api.nolgia.ai/v1/generate/image \
  -H "Authorization: Bearer $NOLGIA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"model":"flux-3-image","prompt":"a paper-cut mountain range at dawn"}'
curl -sS "https://api.nolgia.ai/v1/jobs/<id from the response>/wait?timeout_seconds=120" \
  -H "Authorization: Bearer $NOLGIA_TOKEN"
curl -sS -o first.png "<asset.signed_url from the finished job>"
shell
nolgia gen image --model flux-3-image --prompt "a paper-cut mountain range at dawn" --out first.png
TypeScript
import { writeFile } from "node:fs/promises";
import { createNolgiaClient } from "@nolgia/sdk";

const nolgia = createNolgiaClient(process.env.NOLGIA_TOKEN!);

async function finish(id: string, timeout: number) {
  for (;;) {
    const { data, response } = await nolgia.GET("/jobs/{id}/wait", {
      params: { path: { id }, query: { timeout_seconds: timeout } },
    });
    if (response.status === 408) continue; // the wait window closed; the job is still running
    if (data?.status === "succeeded" && data.asset) return data.asset;
    throw new Error(`job ${id} ended ${data?.status ?? response.status}`);
  }
}

async function download(url: string, file: string) {
  await writeFile(file, Buffer.from(await (await fetch(url)).arrayBuffer()));
}

const { data: image, error } = await nolgia.POST("/generate/image", {
  body: { model: "flux-3-image", prompt: "a paper-cut mountain range at dawn", num_images: 1 },
});
if (error) throw new Error(`${error.title}: ${error.detail ?? ""}`);
await download((await finish(image.id, 120)).signed_url, "first.png");
console.log("image job", image.id, "-> first.png");
Python
import os
import httpx
from nolgia import AuthenticatedClient
from nolgia.api.generate import generate_image, generate_video
from nolgia.api.jobs import wait_for_job
from nolgia.models import GenerateImageRequest, GenerateVideoRequest, ImageModel, Job, VideoModel

client = AuthenticatedClient(base_url="https://api.nolgia.ai/v1", token=os.environ["NOLGIA_TOKEN"])


def finish(job_id, timeout):
    while True:
        response = wait_for_job.sync_detailed(job_id, client=client, timeout_seconds=timeout)
        if response.status_code == 408:  # the wait window closed while the job was still running
            continue
        done = response.parsed
        if isinstance(done, Job) and done.status == "succeeded":
            return done.asset
        raise SystemExit(f"job {job_id} {getattr(done, 'status', done)}")


def download(url, path):
    with open(path, "wb") as f:
        f.write(httpx.get(url).content)


job = generate_image.sync(client=client, body=GenerateImageRequest(model=ImageModel("flux-3-image"), prompt="a paper-cut mountain range at dawn"))
if not isinstance(job, Job):
    raise SystemExit(f"refused: {job}")
download(finish(job.id, 120).signed_url, "first.png")
print("image job", job.id, "-> first.png")
Rustsrc/main.rs
use nolgia::tokio;

#[tokio::main]
async fn main() -> nolgia::Result<()> {
    let nolgia = nolgia::Client::from_env()?;

    let image = nolgia
        .subscribe(nolgia::image("flux-3-image", "a paper-cut mountain range at dawn"))
        .await?;
    nolgia.download(image.url().expect("an image"), "first.png").await?;
    println!("image job {} -> first.png", image.job.id);

    Ok(())
}

Your first video #

This step requires a Pro plan or higher: veo-3.1-lite is not available on Starter.

Generate four seconds at 720p with sound using veo-3.1-lite; append the TypeScript and Python code to the program above, or insert the Rust block before Ok(()) in main.

shell
curl -sS https://api.nolgia.ai/v1/generate/video \
  -H "Authorization: Bearer $NOLGIA_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"model":"veo-3.1-lite","prompt":"a paper-cut mountain range at dawn, slow push-in as the sun rises","duration_seconds":4}'
curl -sS "https://api.nolgia.ai/v1/jobs/<id from the response>/wait?timeout_seconds=300" \
  -H "Authorization: Bearer $NOLGIA_TOKEN"
curl -sS -o first.mp4 "<asset.signed_url from the finished job>"
shell
nolgia gen video --model veo-3.1-lite --prompt "a paper-cut mountain range at dawn, slow push-in as the sun rises" --duration-seconds 4 --out first.mp4
TypeScript
const { data: video, error: videoError } = await nolgia.POST("/generate/video", {
  body: { model: "veo-3.1-lite", prompt: "a paper-cut mountain range at dawn, slow push-in as the sun rises", duration_seconds: 4 },
});
if (videoError) throw new Error(`${videoError.title}: ${videoError.detail ?? ""}`);
await download((await finish(video.id, 300)).signed_url, "first.mp4");
console.log("video job", video.id, "-> first.mp4");
Python
job = generate_video.sync(client=client, body=GenerateVideoRequest(model=VideoModel("veo-3.1-lite"), prompt="a paper-cut mountain range at dawn, slow push-in as the sun rises", duration_seconds=4))
if not isinstance(job, Job):
    raise SystemExit(f"refused: {job}")
download(finish(job.id, 300).signed_url, "first.mp4")
print("video job", job.id, "-> first.mp4")
Rust
    let video = nolgia
        .subscribe(
            nolgia::video("veo-3.1-lite", "a paper-cut mountain range at dawn, slow push-in as the sun rises")
                .set("duration_seconds", 4),
        )
        .await?;
    nolgia.download(video.url().expect("a video"), "first.mp4").await?;
    println!("video job {} -> first.mp4", video.job.id);

Wait, then download #

A job moves from queued to running, then reaches succeeded, failed or canceled. GET /jobs/{id}/wait holds the connection up to timeout_seconds (maximum 900) and answers 408 when the window closes while the job is still running. Download from asset.signed_url, a time-limited URL.

Parameter In Required Description
id path Yes Job UUID.
timeout_seconds query No
The job lifecycle Your app submits a video generation job, the Nolgia API accepts it as queued, runs it, and it ends as succeeded or failed (or canceled, when its owner stops it), after which credits are settled. Your app long-polls the wait endpoint while the job runs. Your app Nolgia API POST /generate/video GET /jobs/{id}/wait 202 Accepted job queued running succeeded failed + failure.code settle: credits released or charged long-poll, up to 120 s per call
Submit a generation, wait while it runs, then read the result

What it costs #

Model id Modality Plan Credits
flux-3-image image starter 3 per image
veo-3.1-lite video pro 14 per clip (5 s)

POST /jobs/cost quotes the exact credits for your settings before you submit (a four-second veo-3.1-lite clip quoted 12 credits on 2026-09-20; the table shows the per-clip baseline); see Billing.

Where next #