API/Generate Thumbnail API

Generate Thumbnail API

Start an AI thumbnail generation job via the REST API.

Start an AI thumbnail generation job. The endpoint returns immediately with a generationId; poll GET /api/v1/generations/:id until status is succeeded or failed to retrieve the final 1280 × 720 PNG URLs.

Endpoint

POST /api/v1/generate

Authentication

Create an org API key from your organisation settings:

/orgs/{orgSlug}/settings/api-keys

Pass the key as a Bearer token or x-api-key header on every request:

Authorization: Bearer nsk_YOUR_KEY
x-api-key: nsk_YOUR_KEY

Request body

FieldTypeRequiredDefaultDescription
promptstringYesNatural-language description of the thumbnail.
modelstringNogemini-3-pro"gemini-3-pro" (free tier) or "gpt-image-2" (paid plan).
countnumberNo1Variations to generate (1–4).
personIdsstring[]No[]Person profile IDs for face consistency.
inspirationIdsstring[]No[]Inspiration IDs to reference for style.
aspectRatiostringNo"16:9"Output aspect ratio. YouTube standard is "16:9".

Response

FieldTypeDescription
generationIdstringOpaque ID — use this to poll status.
thumbnailIdsstring[]IDs for each thumbnail variation (one per count).
statusstringAlways "processing" on this response.

Credit billing

Each call consumes count × model_cost credits from your organisation balance, exactly as an in-app generation would. BYO-key orgs (managed mode off) are not charged. Insufficient balance returns a 402 error before any generation starts.

Rate limits

LayerScopeLimit
A (Better-Auth)Per API key1 000 requests / hour
B (generation window)Per API key10 requests / 60 seconds

Both layers return 429 when exceeded. Layer B is tighter because generation calls are expensive; a single 4-variation call comfortably fits within it.

Examples

cURL

curl -X POST https://fatthumb.klaas.pro/api/v1/generate \
  -H "Authorization: Bearer nsk_YOUR_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "A focused developer at a laptop with neon code on a dark background",
    "model": "gemini-3-pro",
    "count": 2
  }'

JavaScript

const response = await fetch("https://fatthumb.klaas.pro/api/v1/generate", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.FATTHUMB_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    prompt: "A focused developer at a laptop with neon code on a dark background",
    count: 2,
  }),
});

if (!response.ok) {
  const err = await response.json();
  throw new Error(`Generate failed: ${err.message} (${err.code})`);
}

const { generationId } = await response.json();
// Poll GET /api/v1/generations/:generationId for results.

Python

import os, requests, time

resp = requests.post(
    "https://fatthumb.klaas.pro/api/v1/generate",
    headers={
        "Authorization": f"Bearer {os.environ['FATTHUMB_API_KEY']}",
        "Content-Type": "application/json",
    },
    json={"prompt": "Viral YouTube Dev thumbnail with big text", "count": 1},
)
resp.raise_for_status()
generation_id = resp.json()["generationId"]

# Poll until done.
while True:
    poll = requests.get(
        f"https://fatthumb.klaas.pro/api/v1/generations/{generation_id}",
        headers={"Authorization": f"Bearer {os.environ['FATTHUMB_API_KEY']}"},
    )
    data = poll.json()
    if data["status"] in ("succeeded", "failed", "partial"):
        break
    time.sleep(3)

Errors

StatusCodeDescription
401unauthorizedMissing or invalid API key.
402insufficient_balanceNot enough credits. Top up your balance.
402model_requires_paid_plangpt-image-2 requires a Pro or Ultra plan.
402count_exceeds_planRequested variation count exceeds your plan.
402cogs_cap_reachedMonthly generation cap reached.
402platform_cap_reachedPlatform-wide capacity cap reached. Retry later.
402org_blockedYour organisation has been suspended.
402model_requires_openai_keyBYO-key mode: no OpenAI key configured for gpt-image-2.
402model_requires_gemini_keyBYO-key mode: no Gemini key configured for gemini-3-pro.
402generation_deniedGeneration denied by an organisation-level gate.
422content_rejectedPrompt rejected by content policy (pre-charge — no credits consumed).
422consent_withdrawnA referenced person profile has withdrawn consent.
422validation_errorRequest body failed schema validation.
429rate_limitedRate limit exceeded. Retry after a moment.
500internal_errorUnexpected server error.
Get Organization Member APIGet Generation Status API