# NoCam API > One key for AI photo, video and text models, by REST and MCP. Ask for a model by name: we pick the cheapest route that works, move to the next if it fails, and give the credits back if none can do it. Base URL: `https://api.nocamclub.com/v1`. MCP: `https://mcp.nocamclub.com/mcp`. Auth: `Authorization: Bearer nc_live_…` spends credits, `nc_test_…` is a free sandbox with sample results. 1 credit = $0.01. The flow: `GET /v1/models/{id}` gives a model's options (`input_schema`) and `prices`, so never guess them. `POST /v1/estimate` checks a request and prices it for free. `POST /v1/generations` with an `Idempotency-Key` starts it and charges. Photos: add `Prefer: wait=60`. Videos: poll `GET /v1/generations/{id}` every `poll_after_ms`. A failed generation gives its credits back by itself. Files in prompts are `img1`, `video1`, `audio1`. Result links last 7 days: download what you keep. Never top up on your own: send the person to `top_up_url`. Read [For AI agents](https://docs.nocamclub.com/for-ai-agents.md) before anything else. Machine-readable: [OpenAPI 3.1](https://docs.nocamclub.com/openapi.json), [everything in one file](https://docs.nocamclub.com/llms-full.txt). Any page as Markdown: add `.md` to its address. ## Start here - [NoCam API](https://docs.nocamclub.com/index.md): One key for AI photo, video and text models, by REST and MCP. - [Quickstart](https://docs.nocamclub.com/quickstart.md): From a key to your first photo and video, in five minutes. - [For AI agents](https://docs.nocamclub.com/for-ai-agents.md): Everything an AI agent needs to use this API without guessing. Hand this page to yours. ## Basics - [Key concepts](https://docs.nocamclub.com/concepts.md): The few words you need to read everything else here. - [Authentication](https://docs.nocamclub.com/authentication.md): One header on every call. - [Sandbox](https://docs.nocamclub.com/sandbox.md): The whole API, for free, with sample results. - [Content rules](https://docs.nocamclub.com/rules.md): What this API won't make, and what happens when a request asks for it. ## API - [Generations](https://docs.nocamclub.com/api/generations.md): Start one, wait for it, read the result, cancel or delete it. - [Models API](https://docs.nocamclub.com/api/models.md): What's on sale, which options each model takes, and what it costs. - [Uploads](https://docs.nocamclub.com/api/uploads.md): Get your photos, videos and audio to a model. - [Files in prompts](https://docs.nocamclub.com/api/files-in-prompts.md): How a prompt points at your photos, videos and audio. - [Account](https://docs.nocamclub.com/api/account.md): Your balance and limits, as the key you're using sees them. - [Idempotency](https://docs.nocamclub.com/api/idempotency.md): How to retry without paying twice. - [Limits](https://docs.nocamclub.com/api/limits.md): How much, how fast, and what happens past it. - [Errors](https://docs.nocamclub.com/errors.md): Every code the API can answer with, what it means and what to do. ## MCP - [Connect through MCP](https://docs.nocamclub.com/mcp.md): Give Claude Code, Cursor and other agents the whole API as tools. - [MCP tools](https://docs.nocamclub.com/mcp/tools.md): Every tool the MCP server gives an agent. ## Models - [Choose a model](https://docs.nocamclub.com/models.md): Which model for which job, and every model on sale. - [Nano Banana 2](https://docs.nocamclub.com/models/nano-banana-2.md): A strong all-rounder for photos, from text or from your own photos. Fast and cheap, up to 4K. - [Nano Banana Pro](https://docs.nocamclub.com/models/nano-banana-pro.md): The same subject from different angles and in different places. Our choice for keeping a look across a series. - [GPT Image 2.5 Flare](https://docs.nocamclub.com/models/gpt-image-2.5-flare.md): Portraits and clean compositions from your photos. Takes more photos at once than GPT Image 2. - [GPT Image 2](https://docs.nocamclub.com/models/gpt-image-2.md): Anything with exact words on it: posters, signs, covers. Also strong from text alone. - [Muse Video](https://docs.nocamclub.com/models/muse-video.md): A talking clip from one photo, nearly free. Always 10 seconds, always with sound. - [GPT Image 2.5 Sunburst](https://docs.nocamclub.com/models/gpt-image-2.5-sunburst.md): Bold graphic results: stickers, icons, punchy compositions. - [Grok Imagine](https://docs.nocamclub.com/models/grok-imagine.md): A photo from text alone, at the lowest price. Good for drafts and for many tries. - [Grok Imagine Quality](https://docs.nocamclub.com/models/grok-imagine-quality.md): The better Grok, and it takes your photos. - [Seedream 5.0 Flash](https://docs.nocamclub.com/models/seedream-5.0-flash.md): Cheap and quick, and it takes many reference photos at no extra cost. The price is the same at 1K and 2K. - [Seedream 5.0 Pro](https://docs.nocamclub.com/models/seedream-5.0-pro.md): Seedream with more detail, when Flash isn't enough. The price follows the size. - [Omni Flash](https://docs.nocamclub.com/models/omni-flash.md): A short clip with sound, from text or from up to 3 photos, at a very good price. With a video in, it changes that video. - [Seedance 2.0 Fast](https://docs.nocamclub.com/models/seedance-2.0-fast.md): Seedance for less, up to 15 seconds. The usual choice when you don't need 1080p or longer clips. - [Seedance 2.5](https://docs.nocamclub.com/models/seedance-2.5.md): Our strongest video model: up to 30 seconds and 1080p, with photos, videos and audio as references. - [GPT-6 Luna](https://docs.nocamclub.com/models/gpt-6-luna.md): A quick, cheap text model that can look at photos. Good for drafting prompts, captions and short answers. - [Claude Opus 5.5](https://docs.nocamclub.com/models/claude-opus-5.5.md): A strong text model for harder writing and reasoning. ## Guides - [From a photo to a talking clip](https://docs.nocamclub.com/guides/photo-to-clip.md): Two calls. Make the picture you want, then make it speak. - [The same character across many photos](https://docs.nocamclub.com/guides/same-character.md): How to keep a person or a mascot looking like themselves from shot to shot. ## More - [Changelog](https://docs.nocamclub.com/changelog.md): What changed in the API. --- # NoCam API > One key for AI photo, video and text models, by REST and MCP. Source: https://docs.nocamclub.com/ ![A purple character in a black cap and yellow sunglasses types on a laptop in a dark neon-lit room. Made with this API.](https://docs.nocamclub.com/examples/docs-hero.jpg) Make photos, videos and text from one API, with one key and one balance. Ask for a model by name. We pick the cheapest route that works, move to the next if it fails, and give the credits back if none can do it. > **Are you an AI agent?** Start with [For AI agents](https://docs.nocamclub.com/for-ai-agents.md), or read [llms.txt](https://docs.nocamclub.com/llms.txt) for the map and [llms-full.txt](https://docs.nocamclub.com/llms-full.txt) for everything in one file. Every page here also exists as plain Markdown: add `.md` to its address. ## One call ```bash curl https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Prefer: wait=60" \ -d '{ "model": "gpt-image-2", "input": { "prompt": "A yellow taxi in the rain at night", "resolution": "1K", "aspect_ratio": "16:9" } }' ``` ```json { "id": "gen_01a1b37b65dc7dcd8c060f296add5cf8", "status": "succeeded", "model": "gpt-image-2", "price": { "credits": 4, "usd": "0.04", "charged": true }, "outputs": [{ "type": "image", "url": "https://cdn.nocamclub.com/api/8f3c…/1.png", "width": 1024, "height": 576 }] } ``` ## What you get - **Many models, one shape.** Every model is called the same way, and `GET /v1/models/{id}` says exactly which options it takes. - **A failed route isn't your problem.** A model can have several routes behind it. If one fails, the order moves to the next without you doing anything. - **You pay for results.** A price is charged when a generation starts, and it comes back if the generation fails, is refused or is canceled. - **A paid result isn't lost.** If a model finishes after we stopped waiting, the result still arrives, free of charge. - **Errors that say what to do.** Every error has a code, a hint and a [page of its own](https://docs.nocamclub.com/errors.md), written so an agent can act on it. - **MCP as well as REST.** Connect [Claude Code, Cursor and other agents](https://docs.nocamclub.com/mcp.md) with the same key. ## Where next | You want to | Go to | |---|---| | Make your first generation in 5 minutes | [Quickstart](https://docs.nocamclub.com/quickstart.md) | | Hand this API to an AI agent | [For AI agents](https://docs.nocamclub.com/for-ai-agents.md) | | Pick a model | [Models](https://docs.nocamclub.com/models.md) | | Send your own photos, videos and audio | [Uploads](https://docs.nocamclub.com/api/uploads.md) | | Connect through MCP | [MCP](https://docs.nocamclub.com/mcp.md) | | Generate a client | [OpenAPI document](https://docs.nocamclub.com/openapi.json) | ## Getting access The API is open by invitation for now. Whoever invited you gives you a key and credits. A test key costs nothing and works right away: see [Sandbox](https://docs.nocamclub.com/sandbox.md). --- # Quickstart > From a key to your first photo and video, in five minutes. Source: https://docs.nocamclub.com/quickstart ## 1. Set your key You need a key: `nc_test_…` is free and makes sample results, `nc_live_…` spends credits on real models. ```bash export NOCAM_API_KEY="nc_test_your_key_here" ``` ## 2. See what's on sale No key needed for this one. ```bash curl https://api.nocamclub.com/v1/models ``` Each model has an `id`, an `input_schema` (the options it takes) and `prices`. ## 3. Make a photo `Prefer: wait=60` holds the call until the photo is ready, for up to 60 seconds. **cURL** ```bash curl https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Prefer: wait=60" \ -H "Idempotency-Key: my-first-photo" \ -d '{ "model": "gpt-image-2", "input": { "prompt": "A yellow taxi in the rain at night, a sign that says OPEN LATE", "resolution": "1K", "aspect_ratio": "16:9" } }' ``` **JavaScript** ```js const res = await fetch("https://api.nocamclub.com/v1/generations", { method: "POST", headers: { Authorization: `Bearer ${process.env.NOCAM_API_KEY}`, "Content-Type": "application/json", Prefer: "wait=60", "Idempotency-Key": "my-first-photo", }, body: JSON.stringify({ model: "gpt-image-2", input: { prompt: "A yellow taxi in the rain at night, a sign that says OPEN LATE", resolution: "1K", aspect_ratio: "16:9", }, }), }); const generation = await res.json(); console.log(generation.status, generation.outputs[0]?.url); ``` **Python** ```python import os, requests res = requests.post( "https://api.nocamclub.com/v1/generations", headers={ "Authorization": f"Bearer {os.environ['NOCAM_API_KEY']}", "Prefer": "wait=60", "Idempotency-Key": "my-first-photo", }, json={ "model": "gpt-image-2", "input": { "prompt": "A yellow taxi in the rain at night, a sign that says OPEN LATE", "resolution": "1K", "aspect_ratio": "16:9", }, }, timeout=90, ) generation = res.json() print(generation["status"], generation["outputs"][0]["url"] if generation["outputs"] else None) ``` The answer has `status: "succeeded"` and a link in `outputs[0].url`. If 60 seconds weren't enough you get `202` and `status: "running"`: go to step 5 to poll it. ## 4. Use your own photo Send a public address, or upload the file first (see [Uploads](https://docs.nocamclub.com/api/uploads.md)). In the prompt, call the first photo `img1`, the second `img2`. ```bash curl https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Prefer: wait=60" \ -d '{ "model": "nano-banana-2", "input": { "prompt": "img1 riding a skateboard on a rooftop at sunset, phone photo", "images": ["https://cdn.nocamclub.com/static/test/mascot.jpg"], "resolution": "1K", "aspect_ratio": "3:4" } }' ``` ## 5. Make a video and wait for it Videos take minutes, longer than one call should stay open. Start it, keep the `id`, and poll. **JavaScript** ```js const headers = { Authorization: `Bearer ${process.env.NOCAM_API_KEY}`, "Content-Type": "application/json" }; const started = await fetch("https://api.nocamclub.com/v1/generations", { method: "POST", headers: { ...headers, "Idempotency-Key": "my-first-video" }, body: JSON.stringify({ model: "muse-video", input: { prompt: 'img1 looks at the camera and says: "Hi, this is a quick test."', images: ["https://cdn.nocamclub.com/static/test/mascot.jpg"], }, }), }).then((r) => r.json()); let generation = started; while (generation.status === "queued" || generation.status === "running") { await new Promise((resolve) => setTimeout(resolve, generation.poll_after_ms ?? 3000)); generation = await fetch(generation.urls.self, { headers }).then((r) => r.json()); } if (generation.status === "succeeded") console.log(generation.outputs[0].url); else console.log(generation.error.code, generation.error.message); // The credits are back. ``` **Python** ```python import os, time, requests headers = {"Authorization": f"Bearer {os.environ['NOCAM_API_KEY']}"} generation = requests.post( "https://api.nocamclub.com/v1/generations", headers={**headers, "Idempotency-Key": "my-first-video"}, json={ "model": "muse-video", "input": { "prompt": 'img1 looks at the camera and says: "Hi, this is a quick test."', "images": ["https://cdn.nocamclub.com/static/test/mascot.jpg"], }, }, timeout=60, ).json() while generation["status"] in ("queued", "running"): time.sleep(generation.get("poll_after_ms", 3000) / 1000) generation = requests.get(generation["urls"]["self"], headers=headers, timeout=30).json() if generation["status"] == "succeeded": print(generation["outputs"][0]["url"]) else: print(generation["error"]["code"], generation["error"]["message"]) # The credits are back. ``` ## 6. Keep what you made Result links stop working after 7 days. Download what you want to keep. ## Next - [How generations work](https://docs.nocamclub.com/api/generations.md): statuses, cancel, delete. - [Errors](https://docs.nocamclub.com/errors.md): what each code means and what to do. - [Models](https://docs.nocamclub.com/models.md): which model for which job, and how to write prompts for it. --- # For AI agents > Everything an AI agent needs to use this API without guessing. Hand this page to yours. Source: https://docs.nocamclub.com/for-ai-agents ![A purple character gives a high five to a small white robot on a rooftop at night. Made with this API.](https://docs.nocamclub.com/examples/agents.jpg) This page is for the model doing the work. If you're a person, paste the prompt below into your agent, and it will take it from there. ## Hand it to your agent ```text Use the NoCam API to make photos, videos and text. Read https://docs.nocamclub.com/llms.txt first, and follow the rules on https://docs.nocamclub.com/for-ai-agents.md My key is in the NOCAM_API_KEY environment variable. Never print it. Before spending more than 100 credits in one go, tell me the price and wait for my yes. ``` ## What to read | What | Address | |---|---| | The map: every page in one line | [/llms.txt](https://docs.nocamclub.com/llms.txt) | | Everything in one file | [/llms-full.txt](https://docs.nocamclub.com/llms-full.txt) | | Any page as Markdown | Add `.md`: [/api/generations.md](https://docs.nocamclub.com/api/generations.md) | | The API as OpenAPI 3.1 | [/openapi.json](https://docs.nocamclub.com/openapi.json), also at `https://api.nocamclub.com/v1/openapi.json` | | What's on sale right now, with options and prices | `GET https://api.nocamclub.com/v1/models` | | A skill file for Claude Code and similar agents | [/skills/nocam/SKILL.md](https://docs.nocamclub.com/skills/nocam/SKILL.md) | ## The rules 1. **Don't guess a model's options.** They differ from model to model, and they change with what's on sale. Read `GET /v1/models/{id}`: `input_schema` is the truth, and `prices` lists what can be bought right now. An unknown field is refused, not ignored. 2. **Check before you spend.** `POST /v1/estimate` takes the same body as `POST /v1/generations`, checks everything and gives the price. Nothing runs and nothing is charged. 3. **Always send an `Idempotency-Key`.** Use a new one for each thing you want made, and the same one when you retry it. Then a timeout can't make you pay twice. 4. **Don't start something again to check on it.** Starting is `POST`, and it costs money. Checking is `GET /v1/generations/{id}`, and it's free. Keep the `id`. 5. **Photos: use `Prefer: wait=60`. Videos: poll.** Photos usually finish within a minute. Videos take minutes, so poll every `poll_after_ms`. 6. **Read `error.code` and act on it.** Every error, on a refused call and on a failed generation alike, has `hint` (what to do) and `retryable` (whether the same request can work: on a failed generation, send it with a new `Idempotency-Key`). `docs_url` has more, but you don't need it to decide. 7. **Check `status`, not just the HTTP code.** A generation that fails while you wait with `Prefer: wait` still answers `200`, with `status: "failed"`. 8. **Tell the person when something was refused.** Don't reword a refused prompt to slip past the rules. Refusals count, and twenty in a day pause the account. 9. **Download what should last.** Result links stop working at `expires_at`, 7 days by default. Uploaded files go after 48 hours. 10. **Never top up on your own.** On `insufficient_credits`, send the person to `top_up_url`. 11. **Never print or commit the key.** Read it from the environment. ## The flow ```text GET /v1/models What's on sale? GET /v1/models/{id} What does this model take, and what does it cost? POST /v1/uploads Files: pass {url}, or get a link to PUT to POST /v1/estimate Is this valid, and what's the price? POST /v1/generations Start. Charged now. Send Idempotency-Key. GET /v1/generations/{id} Until status is succeeded, failed or canceled. ``` `status` goes `queued` → `running` → `succeeded`, `failed` or `canceled`. A generation that fails or is canceled gives its credits back by itself: don't try to claim them. ## What to do with an error In short, with the same meaning as `retryable` and `hint`: | What you see | What it means | What to do | |---|---|---| | `invalid_parameter` | A field is wrong. `path` names it and `hint` lists what works | Fix it and send again | | `unknown_model`, `not_for_sale`, `no_route` | Not available with these settings | Pick from `prices` in `GET /v1/models/{id}`, or another model | | `input_refused`, `content_refused` | Against the [content rules](https://docs.nocamclub.com/rules.md), or the model refused | Tell the person. Change the idea, don't reword around it | | `insufficient_credits`, `spend_limit_reached` | Out of credits or over a limit | Tell the person. Send them to `top_up_url` | | `rate_limited`, `too_many_active` | Too fast or too many at once | Wait for `Retry-After`, then send the same request | | `provider_unavailable`, `generation_failed` | The model failed. Credits are back | Try once more with a **new** key, then another model | | `timed_out` | We stopped waiting. Credits are back | Check the same `id` later: the result may still come, free | | `internal` | Our fault | Retry with the **same** `Idempotency-Key` | | `invalid_api_key`, `missing_scope`, `account_suspended` | The key or the account | Stop and tell the person | All of them: [Errors](https://docs.nocamclub.com/errors.md). ## Which model Short version below. Details and prompt tips are on each model's page, starting at [Models](https://docs.nocamclub.com/models.md). | The job | Use | |---|---| | A photo of someone or something from one photo, cheap and good | `nano-banana-2` | | The same character across many photos | `nano-banana-pro` | | A poster or anything with exact words on it | `gpt-image-2` | | Many reference photos at once, cheap | `seedream-5.0-flash` | | A photo from text alone, as cheap as it gets | `grok-imagine` | | A talking clip from one photo, 10 seconds with sound, nearly free | `muse-video` | | A short clip from a photo or text, or changing a clip you have | `omni-flash` | | The best clip, up to 30 s, with photos, video and audio as references | `seedance-2.5` | | The same, cheaper, up to 15 s | `seedance-2.0-fast` | | A text answer | `gpt-6-luna`, or `claude-opus-5.5` for harder work | Always confirm a model is on sale with `GET /v1/models` before relying on this table. ## Writing prompts - **Name your files.** `img1`, `img2`, `video1`, `audio1`, in the order you sent them. See [Files in prompts](https://docs.nocamclub.com/api/files-in-prompts.md). - **Say what to keep and what to change.** Models tend to carry over anything you don't mention, like the background and the clothes in a photo. - **Put speech in quotes**, and keep it short enough to say in the clip's length: about 2 words a second. - **Ask for simple movement.** One action, a still camera. Complicated physics is where clips break. - **Spell out exact words.** For text in a photo, write the words and add that the spelling must be exact. ## Connecting through MCP If your client speaks MCP, you don't need to write any HTTP. See [MCP](https://docs.nocamclub.com/mcp.md). A tool's error comes back as a result you can read, with the same codes and hints. ## Testing without spending A `nc_test_…` key runs the whole API on sample results at no cost, and the word `fail` in a prompt makes the generation fail so you can test your error handling. See [Sandbox](https://docs.nocamclub.com/sandbox.md). --- # Key concepts > The few words you need to read everything else here. Source: https://docs.nocamclub.com/concepts ## Model A named AI model, like `gpt-image-2` or `seedance-2.5`. Its `kind` is `image` (photos), `video` or `text`. See [Models](https://docs.nocamclub.com/models.md). ## Variant and price One buyable combination of a model's settings: `720p`, 5 seconds, with or without a video among the files. Each variant has its own price in `prices`. Prices are whole credits, and they don't move with the prompt. ## Credit The currency. **1 credit = $0.01.** There's one balance for everything. Only paid credits buy models directly: bonus credits are for scenes on the site. See your balance with `GET /v1/account`. ## Generation One order: a model, its `input`, and what came of it. It starts as `queued`, moves to `running`, and ends as `succeeded`, `failed` or `canceled`. Its `outputs` hold the results. See [Generations](https://docs.nocamclub.com/api/generations.md). ## Route One way we can reach a model. A model can have several. The cheapest one goes first, and if it fails the order moves to the next by itself. You never choose a route, and we don't name them. `routes` in a model says how many there are, and `no_fallback: true` means there's one, so if it's down the model is down. ## File A photo, video or audio file for a generation. Send a public https address, or upload it first and use its `file_…` id. See [Uploads](https://docs.nocamclub.com/api/uploads.md). ## Mode: live and test A key is either `nc_live_…` or `nc_test_…`. Live keys spend credits on real models. Test keys are the free [sandbox](https://docs.nocamclub.com/sandbox.md). The two don't see each other's generations. ## Level Your account's limits: how many generations a minute, how many at once, and how many credits a day. See [Limits](https://docs.nocamclub.com/api/limits.md). --- # Authentication > One header on every call. Source: https://docs.nocamclub.com/authentication Send your key on every call: ```http Authorization: Bearer nc_live_abc123… ``` `GET /v1/models`, `GET /v1/models/{id}` and `GET /v1/openapi.json` are open and need no key. ## Two kinds of key | Starts with | What it does | |---|---| | `nc_live_` | Runs real models and spends credits | | `nc_test_` | The [sandbox](https://docs.nocamclub.com/sandbox.md): sample results, no credits | ## What a key can be limited to Whoever makes the key can set: | Limit | What happens past it | |---|---| | Permissions (`models:read`, `generations:read`, `generations:write`, `uploads:write`, `account:read`) | [`missing_scope`](https://docs.nocamclub.com/errors/missing_scope.md) | | A spend limit per day, week, month or in total | [`spend_limit_reached`](https://docs.nocamclub.com/errors/spend_limit_reached.md) | | A list of models | [`model_not_allowed`](https://docs.nocamclub.com/errors/model_not_allowed.md) | | A list of addresses | [`ip_not_allowed`](https://docs.nocamclub.com/errors/ip_not_allowed.md) | | An expiry date | [`expired_api_key`](https://docs.nocamclub.com/errors/expired_api_key.md) | Give an AI agent its own key with a spend limit. If it goes wrong, the damage has a ceiling, and you can revoke that key alone. ## Keeping it safe - Keep it in an environment variable, never in code or in a chat. - A browser page can't keep a secret: call the API from your server. - A key's fixed prefix lets secret scanners spot a leak. If one leaks, have it revoked: it stops working at once. We store only a keyed hash of each key, so a lost key can't be shown again. You get a new one. --- # Sandbox > The whole API, for free, with sample results. Source: https://docs.nocamclub.com/sandbox A key starting with `nc_test_` runs on sample results. Nothing goes to a model and no credits move, so an agent or your tests can run as often as they like. ## What's real and what's sample | Works exactly as in live | Sample | |---|---| | Keys, permissions and rate limits | The result: one fixed photo (430×662), clip (672×1344, 10 s, with sound) or sentence, with the same fields a real one has | | Every check on a request, and every refusal | The price is shown, but `charged` is `false` | | Queue, statuses, `Prefer: wait`, polling, cancel, delete, list | A generation takes about 3 seconds | | Idempotency | | | Uploads: files really go to storage and are really checked | | The sample doesn't follow your prompt or settings: the same photo comes back for a poster and for a 1:1 request. To see what a prompt really does, use a live key. ## Testing failure Put the word `fail` in the prompt, and the generation fails with [`sandbox_failure`](https://docs.nocamclub.com/errors/sandbox_failure.md). Use it to test your error handling. ```bash curl https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_TEST_KEY" \ -H "Content-Type: application/json" \ -H "Prefer: wait=20" \ -d '{ "model": "gpt-image-2", "input": { "prompt": "please fail" } }' ``` ```json { "status": "failed", "mode": "test", "error": { "code": "sandbox_failure", "message": "The sandbox failed this generation because the prompt has the word fail in it. Take the word out to get a sample result.", "hint": "Take the word fail out of the prompt to get a sample result.", "retryable": false, "docs_url": "https://docs.nocamclub.com/errors/sandbox_failure" } } ``` ## Limits 30 generations a minute, 5 in progress at once. Live and test don't see each other: a test key gets [`not_found`](https://docs.nocamclub.com/errors/not_found.md) for a live generation, and the other way around. The sandbox only sells what live does: a model that's not on sale is refused in both. --- # Content rules > What this API won't make, and what happens when a request asks for it. Source: https://docs.nocamclub.com/rules ## What we don't make - **Sexual content.** Nudity, sexual acts, fetish content, or removing someone's clothes. - **Anything sexualising a minor.** A person who looks under 18 in any sexual, romantic or revealing context. Never, in any form. - **Real people without their consent.** Use photos of yourself, or of people who agreed to it. - **Public figures made to say or do something.** Named celebrities and politicians. - **Gore and graphic injury.** - **Hatred against a protected group.** - **Fake IDs, documents or money.** Ordinary portraits, fashion, jokes and flirting without nudity are fine. A photo of a person is fine by itself. ## What happens Every request is checked three times: 1. **At the door.** A short list of words that are never legitimate here answers at once with [`input_refused`](https://docs.nocamclub.com/errors/input_refused.md). You're charged nothing. 2. **By our check.** A model looks at the prompt and the photos before any work starts. A refusal ends the generation with [`content_refused`](https://docs.nocamclub.com/errors/content_refused.md), and the credits come back. 3. **By the model.** Models have rules of their own, and some refuse more than we do, including photos they take for real people. That also ends in `content_refused` or `input_refused`, with the credits back. Refusals count. **Twenty refused requests within 24 hours pause the account**, and every call then answers [`account_suspended`](https://docs.nocamclub.com/errors/account_suspended.md). ## If you're an agent Tell the person what was refused. Don't reword a request to get past the rules: a refused idea stays refused, and each try counts toward the pause. ## What you're responsible for You need the right to use every file you send. When your own customers use your product, pass a pseudonym in `end_user` (never an email), so that one misbehaving customer can be told apart from the rest. --- # Generations > Start one, wait for it, read the result, cancel or delete it. Source: https://docs.nocamclub.com/api/generations A generation is one order: a model, its `input`, and what came of it. ## Start one ```http POST /v1/generations ``` | Field | Needed | What it is | |---|---|---| | `model` | Yes | A model id from [`GET /v1/models`](https://docs.nocamclub.com/api/models.md) | | `input` | Yes | What to make. Its fields depend on the model: read its `input_schema` | | `input.prompt` | Yes | Up to 10,000 characters | | `end_user` | No | Your own id for your customer. A pseudonym, never an email | | `metadata` | No | Your notes, strings up to 500 characters. They come back with the generation | | `retention_hours` | No | Remove results sooner than the default 7 days: 1 to 168 | Fields of `input` that a model can take: `aspect_ratio`, `resolution`, `quality`, `output_format`, `duration`, `reference_mode`, `images`, `videos`, `audios`. An unknown field is refused, not ignored. Headers: | Header | What it does | |---|---| | `Idempotency-Key` | Recommended always. See [Idempotency](https://docs.nocamclub.com/api/idempotency.md) | | `Prefer: wait=60` | Holds the call until it's done, up to that many seconds, 60 at most | The price is charged now. The answer is `202` with a generation to poll, or `200` if it finished within your `Prefer: wait`. Response headers: | Header | What it says | |---|---| | `X-Credits-Charged` | Credits this call took: the price on a new live generation, `0` on a repeat and on a test key | | `Idempotent-Replayed` | `true` when this is a repeat of an earlier request | | `X-Request-Id` | Always. Quote it if you contact us | ## Follow it ```http GET /v1/generations/{id} ``` ```text queued -> running -> succeeded -> failed (credits back) -> canceled (credits back) ``` Poll every `poll_after_ms`, which is 3 seconds today. It's only there while the generation is in progress. ## The result ```json { "id": "gen_01a1b37b65dc7dcd8c060f296add5cf8", "object": "generation", "model": "muse-video", "status": "succeeded", "mode": "live", "price": { "credits": 2, "usd": "0.02", "charged": true }, "params": {}, "outputs": [ { "type": "video", "url": "https://cdn.nocamclub.com/api/8f3c…/1.mp4", "content_type": "video/mp4", "bytes": 1932156, "width": 768, "height": 1152, "duration_seconds": 10, "has_audio": true, "expires_at": "2026-11-14T00:55:00.000Z" } ], "error": null, "recovered": false, "purged": false, "timing": { "total_ms": 72000 }, "urls": { "self": "https://api.nocamclub.com/v1/generations/gen_01a1b37b65dc7dcd8c060f296add5cf8" }, "created_at": "2026-11-07T00:54:00.000Z", "finished_at": "2026-11-07T00:55:12.000Z" } ``` - A photo or video output has a `url`. A text output has `text` instead: `{ "type": "text", "text": "…" }`. - `params` shows the settings it ran with, defaults filled in. - `price.charged` is `false` once the credits have come back, and always on a test key. ## When it fails `status` is `failed`, `error.message` says why, `error.hint` what to do, and `error.retryable` whether the same request can work (send it with a new `Idempotency-Key`). The credits are already back. With `Prefer: wait` this still answers `200`, so check `status`. See [Errors](https://docs.nocamclub.com/errors.md). ```json { "status": "failed", "error": { "code": "provider_unavailable", "message": "No route can run this model right now. Your credits came back. Try again in a few minutes.", "hint": "Try the same request in a few minutes, or another model.", "retryable": true, "docs_url": "https://docs.nocamclub.com/errors/provider_unavailable" } } ``` **A late result isn't lost.** If a model finishes after we stopped waiting, we keep checking for a day. If it comes, the generation turns to `succeeded` with `recovered: true`, and you keep the refund. ## List them ```http GET /v1/generations?status=succeeded&model=gpt-image-2&limit=20&cursor=… ``` Newest first. `has_more` and `next_cursor` page through. You see only your own account's, in the key's mode. ## Cancel one ```http POST /v1/generations/{id}/cancel ``` Works while no model has it yet, and the credits come back. After that it answers [`not_cancelable`](https://docs.nocamclub.com/errors/not_cancelable.md): the generation finishes and is billed. ## Delete one ```http DELETE /v1/generations/{id} ``` Removes the files and the prompt now, without waiting for them to expire. Only finished generations: otherwise [`not_finished`](https://docs.nocamclub.com/errors/not_finished.md). --- # Models API > What's on sale, which options each model takes, and what it costs. Source: https://docs.nocamclub.com/api/models Both calls are open: no key, up to 60 calls a minute per address. ```http GET /v1/models GET /v1/models?kind=video GET /v1/models/{id} ``` `kind` is `image` (photos), `video` or `text`. ## What a model says about itself ```json { "id": "muse-video", "object": "model", "name": "Muse Video", "kind": "video", "family": "Meta", "description": "…", "input_schema": { "$schema": "https://json-schema.org/draft/2020-12/schema", "type": "object", "required": ["prompt"], "additionalProperties": false, "properties": { "prompt": { "type": "string", "minLength": 1, "maxLength": 10000 }, "aspect_ratio": { "type": "string", "enum": ["9:16", "16:9", "1:1"], "default": "9:16" }, "images": { "type": "array", "maxItems": 1, "items": { "type": "string" } } } }, "prices": [{ "credits": 2, "usd": "0.02" }], "routes": 1, "no_fallback": true, "stats": null } ``` | Field | What it tells you | |---|---| | `input_schema` | JSON Schema of `input`, limited to what can be made right now. Validate against it, or build a form from it | | `prices` | Every combination you can buy now. If it isn't here, it can't be bought now | | `prices[].with_video` | This price applies when a video is among your files | | `routes`, `no_fallback` | How many routes can serve it. With one, the model is down when that route is | | `stats` | Over 7 days of orders through the API: `median_seconds`, `p90_seconds`, `success_rate`, `samples`. `null` until there are some | The catalog changes: routes go on and off, and models come and go. Read it rather than remembering it. ## Pricing a request To price one exact request with its files, use the estimate. It takes the same body as `POST /v1/generations`, runs every check, and charges nothing. ```bash curl https://api.nocamclub.com/v1/estimate \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "seedance-2.5", "input": { "prompt": "A paper boat in a gutter", "duration": 5 } }' ``` ```json { "object": "estimate", "valid": true, "model": "seedance-2.5", "params": { "aspect_ratio": "9:16", "resolution": "720p", "duration": 5 }, "credits": 60, "usd": "0.60" } ``` `params` shows the settings it would run with, defaults filled in, spelled as in a request. ## Pick one [Models](https://docs.nocamclub.com/models.md) has which model for which job, and a page per model with prompt tips. --- # Uploads > Get your photos, videos and audio to a model. Source: https://docs.nocamclub.com/api/uploads A file goes into `images`, `videos` or `audios` of a generation as either a public https address or a `file_…` id. | | Formats | Up to | |---|---|---| | Photo | PNG, JPEG, WebP | 10 MB | | Video | MP4, MOV (some models: MP4 only) | 50 MB | | Audio | MP3, WAV | 15 MB | How many files and how long they may be depends on the model: see `maxItems` and the descriptions in its `input_schema`. The file's first bytes decide what it is, not its name or the type you claim. ## Three ways ### 1. Just pass an address The simplest. We fetch it when you start the generation. ```json { "model": "nano-banana-2", "input": { "prompt": "img1 on a rooftop", "images": ["https://example.com/me.jpg"] } } ``` ### 2. Have us fetch it first Do this when you'll use the file several times, or want to know it's good before you start. ```bash curl https://api.nocamclub.com/v1/uploads \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://example.com/clip.mp4" }' ``` ```json { "id": "file_01a1b37b65dc7dcd8c060f296add5cf8", "object": "file", "kind": "video", "content_type": "video/mp4", "bytes": 4581035, "duration_seconds": 8, "status": "ready", "expires_at": "2026-11-09T00:00:00.000Z" } ``` We only fetch public https addresses: never `localhost` or a private network. ### 3. Upload from your machine For local files and anything big. Files go straight to storage, not through our API. ```bash # 1. Ask for a link, saying what you'll send curl https://api.nocamclub.com/v1/uploads \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "content_type": "video/mp4", "bytes": 4581035 }' # -> { "id": "file_…", "upload_url": "https://…", "upload_method": "PUT", "upload_headers": { "content-type": "video/mp4" }, … } # 2. PUT the file there, with that content type, within 15 minutes curl -X PUT -H "content-type: video/mp4" --upload-file clip.mp4 "$UPLOAD_URL" # 3. Have it checked: gives you the length, and refuses a bad file now rather than later curl -X POST https://api.nocamclub.com/v1/uploads/$FILE_ID/complete \ -H "Authorization: Bearer $NOCAM_API_KEY" ``` Step 3 is optional: a file is checked the first time a generation uses it. A file is `pending` from step 1 until it's checked, with `bytes` still `null`, and `ready` after. Fetching by address (way 2) gives a `ready` file at once. ## After that - **Files stay for 48 hours**, then they're removed. Using an old one answers `invalid_parameter`: upload it again. - **Only your account can use your files.** Another account's id is simply not found. - `GET /v1/uploads/{id}` shows a file's state. ## Length limits A video or audio file's length is read when it's uploaded. If it's over the model's limit, the generation is refused with [`invalid_parameter`](https://docs.nocamclub.com/errors/invalid_parameter.md) before anything is charged. Video limits are for all the videos of a request together, and the same file sent twice counts twice. Audio limits are per file. If a file's length can't be read, the request goes ahead and the model decides. A refusal gives the credits back. ## What can go wrong | Code | Why | |---|---| | [`file_too_large`](https://docs.nocamclub.com/errors/file_too_large.md) | Over the size limit above | | [`unsupported_media`](https://docs.nocamclub.com/errors/unsupported_media.md) | It isn't one of those formats, whatever its name says | | [`upload_not_found`](https://docs.nocamclub.com/errors/upload_not_found.md) | `/complete` came before the file did | | [`invalid_parameter`](https://docs.nocamclub.com/errors/invalid_parameter.md) | The address can't be fetched, or a file isn't yours, is the wrong kind or has expired | | [`bad_input_file`](https://docs.nocamclub.com/errors/bad_input_file.md) | The model itself couldn't read it, after the generation started | --- # Files in prompts > How a prompt points at your photos, videos and audio. Source: https://docs.nocamclub.com/api/files-in-prompts In a prompt, refer to files by their position in the request: | In your prompt | Means | |---|---| | `img1`, `img2` | The first and second of `images` | | `video1` | The first of `videos` | | `audio1` | The first of `audios` | ```json { "model": "seedance-2.5", "input": { "prompt": "img1 walks through the city from img2, moving like the dancer in video1, to the rhythm of audio1", "images": ["file_person", "file_city"], "videos": ["file_dance"], "audios": ["file_track"], "duration": 10 } } ``` We rewrite these into the wording each model is documented to understand, so the same prompt works everywhere. Your prompt stays as you wrote it on the generation. ## How a clip uses photos: `reference_mode` For video models that have a choice: | Mode | What it does | `img1` means | |---|---|---| | `ingredients` | The model takes what it needs: people, places, things. The clip doesn't have to start on the photo | The first photo | | `frames` | The first photo is the opening frame, and the second, if the model takes one, is the closing frame | The first frame. `img2` is the last frame | | `start` | The first photo opens the clip, and the rest are ingredients | The opening frame. `img2` is the first ingredient | Videos and audio always go with `ingredients`. ## Good habits - Say what each file is for, as in the example. A model that's told "the person from img1" does better than one left to work it out. - Say what to keep and what to change. Anything you don't mention tends to carry over from the photo: background, clothes, light. --- # Account > Your balance and limits, as the key you're using sees them. Source: https://docs.nocamclub.com/api/account ```http GET /v1/account ``` ```json { "object": "account", "mode": "live", "level": "start", "credits": { "spendable_on_models": 1250, "bonus": 0 }, "limits": { "per_minute": 10, "in_progress": 2, "credits_per_day": 2500 }, "top_up_url": "https://nocamclub.com/account/credits" } ``` | Field | What it is | |---|---| | `mode` | `live` or `test`, from the key | | `level` | Your account's level. A test key always says `sandbox`. See [Limits](https://docs.nocamclub.com/api/limits.md) | | `credits.spendable_on_models` | Credits that can buy models through this API. 1 credit = $0.01 | | `credits.bonus` | Bonus credits. They work for scenes on the site, not for models directly | | `limits.per_minute` | New generations a minute | | `limits.in_progress` | Generations in progress at once | | `limits.credits_per_day` | Credits a day, UTC, or the key's own lower limit if it has one | | `top_up_url` | Where a person tops up | Needs the `account:read` permission. ## Before a big job Check `spendable_on_models` against the price from [`POST /v1/estimate`](https://docs.nocamclub.com/api/models.md#pricing-a-request) first. If it isn't enough, the generation is refused with [`insufficient_credits`](https://docs.nocamclub.com/errors/insufficient_credits.md) and nothing is charged. An agent should never top up on its own: send the person to `top_up_url`. --- # Idempotency > How to retry without paying twice. Source: https://docs.nocamclub.com/api/idempotency Networks fail. If a call times out, you can't know whether the generation started. An `Idempotency-Key` makes retrying safe. ```http POST /v1/generations Idempotency-Key: order-1234-hero-photo ``` | You send | You get | |---|---| | A new key | A new generation | | The same key and the same body | The first generation, with `Idempotent-Replayed: true`. Nothing new is charged | | The same key and another body | [`idempotency_conflict`](https://docs.nocamclub.com/errors/idempotency_conflict.md) | - Up to 200 characters. Keys belong to your account. - A key is remembered for as long as its generation exists, which is for good: deleting a generation removes its files, not the record. So never reuse a key for new work. - Use one key for each thing you want made: an order id, a UUID, a hash of what you're asking for. Keys in these docs' examples are examples: make your own. - **A refused call doesn't use up its key.** If the answer is a 4xx, nothing was made: fix the request and send it again with the same key. - **To retry a failed generation, use a new key.** The old key returns the same failure, because it's the same order. - After [`internal`](https://docs.nocamclub.com/errors/internal.md) or a dropped connection, retry with the **same** key. ## Through MCP The `generate` tool has no key field: it does this for you. A call with exactly the same arguments within the same 10 minutes returns the same generation, unless that one failed or was deleted. Pass `run_again: true` to make another on purpose. --- # Limits > How much, how fast, and what happens past it. Source: https://docs.nocamclub.com/api/limits ## Levels Your account has a level. See yours with `GET /v1/account`. | Level | New generations a minute | In progress at once | Credits a day | |---|---|---|---| | Sandbox (test keys) | 30 | 5 | Free | | Start | 10 | 2 | 2,500 | | Build | 60 | 5 | 10,000 | | Scale | 300 | 20 | 100,000 | | Custom | 600 | 50 | 1,000,000 | ## Other limits | What | Limit | |---|---| | All calls with one key | 600 a minute | | Uploads with one key | 60 a minute | | The open catalog, per address | 60 a minute | | Request body | 1 MB. Files go through [Uploads](https://docs.nocamclub.com/api/uploads.md) | | `Prefer: wait` | 60 seconds | | A prompt | 10,000 characters | The day runs on UTC and resets at 00:00. A key can have its own spend limit on top: see [Authentication](https://docs.nocamclub.com/authentication.md). ## Past a limit | Code | What to do | |---|---| | [`rate_limited`](https://docs.nocamclub.com/errors/rate_limited.md) | Wait for `Retry-After`, then send the same request | | [`too_many_active`](https://docs.nocamclub.com/errors/too_many_active.md) | Wait for one to finish | | [`spend_limit_reached`](https://docs.nocamclub.com/errors/spend_limit_reached.md) | Wait for the reset, or raise the limit | ## How long things stay | What | How long | |---|---| | Results | 7 days. Links stop at `expires_at`, and `retention_hours` can make it shorter | | Uploaded files | 48 hours | Download what you want to keep. Result links are public but impossible to guess: anyone with the link can open it, so treat it like a secret if it matters. --- # Errors > Every code the API can answer with, what it means and what to do. Source: https://docs.nocamclub.com/errors There are two places an error can appear. Neither one costs credits. ## Refused at once The call answers with an HTTP error, and nothing started: ```json { "error": { "code": "invalid_parameter", "message": "gpt-image-2 doesn't support aspect ratio 5:4.", "path": "input.aspect_ratio", "hint": "Use one of: 1:1, 16:9, 9:16, 4:3, 3:4, 3:2, 2:3, 21:9.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/invalid_parameter" } } ``` | Field | What it is | |---|---| | `code` | Stable, safe to write code against | | `message` | What happened, for people and agents | | `path` | The field at fault | | `hint` | What to do about it | | `retryable` | Whether the same request can work, after any wait the error names | | `request_id` | Quote this if you contact us | | `docs_url` | A page about this code | Some codes add fields, such as `credits`, `balance` and `top_up_url` on `insufficient_credits`, or `limit` on `rate_limited`. | Code | HTTP | Meaning | Worth retrying? | |---|---|---|---| | [`invalid_request`](https://docs.nocamclub.com/errors/invalid_request.md) | 400 | The request can't be read | After a change | | [`invalid_parameter`](https://docs.nocamclub.com/errors/invalid_parameter.md) | 400 | A field is wrong | After a change | | [`unknown_model`](https://docs.nocamclub.com/errors/unknown_model.md) | 400 | That model isn't on sale | After a change | | [`input_refused`](https://docs.nocamclub.com/errors/input_refused.md) | 400 | Refused by content rules | After a change | | [`invalid_api_key`](https://docs.nocamclub.com/errors/invalid_api_key.md) | 401 | The key isn't valid | No | | [`expired_api_key`](https://docs.nocamclub.com/errors/expired_api_key.md) | 401 | The key has expired | No | | [`insufficient_credits`](https://docs.nocamclub.com/errors/insufficient_credits.md) | 402 | Not enough credits | No | | [`account_suspended`](https://docs.nocamclub.com/errors/account_suspended.md) | 403 | The account is paused | No | | [`ip_not_allowed`](https://docs.nocamclub.com/errors/ip_not_allowed.md) | 403 | Not from this address | No | | [`missing_scope`](https://docs.nocamclub.com/errors/missing_scope.md) | 403 | The key can't do this | No | | [`model_not_allowed`](https://docs.nocamclub.com/errors/model_not_allowed.md) | 403 | The key can't use this model | No | | [`origin_not_allowed`](https://docs.nocamclub.com/errors/origin_not_allowed.md) | 403 | Not from this page | After a change | | [`spend_limit_reached`](https://docs.nocamclub.com/errors/spend_limit_reached.md) | 403 | A spend limit is reached | No | | [`not_found`](https://docs.nocamclub.com/errors/not_found.md) | 404 | Not found | After a change | | [`idempotency_conflict`](https://docs.nocamclub.com/errors/idempotency_conflict.md) | 409 | This key was used with another request | After a change | | [`no_route`](https://docs.nocamclub.com/errors/no_route.md) | 409 | No route can do this right now | After a change | | [`not_cancelable`](https://docs.nocamclub.com/errors/not_cancelable.md) | 409 | Too late to cancel | After a change | | [`not_finished`](https://docs.nocamclub.com/errors/not_finished.md) | 409 | Still in progress | Yes | | [`not_for_sale`](https://docs.nocamclub.com/errors/not_for_sale.md) | 409 | Not on sale with these settings | After a change | | [`upload_not_found`](https://docs.nocamclub.com/errors/upload_not_found.md) | 409 | The file isn't there yet | Yes | | [`file_too_large`](https://docs.nocamclub.com/errors/file_too_large.md) | 413 | The file is too big | After a change | | [`unsupported_media`](https://docs.nocamclub.com/errors/unsupported_media.md) | 415 | We can't read this file | After a change | | [`rate_limited`](https://docs.nocamclub.com/errors/rate_limited.md) | 429 | Too many requests | Yes | | [`too_many_active`](https://docs.nocamclub.com/errors/too_many_active.md) | 429 | Too many in progress | Yes | | [`internal`](https://docs.nocamclub.com/errors/internal.md) | 500 | Something went wrong on our side | Yes | | [`platform_paused`](https://docs.nocamclub.com/errors/platform_paused.md) | 503 | The API is paused | Yes | ## On a failed generation The call was accepted, and later the generation ended with `status: "failed"`. The credits are already back. ```json { "status": "failed", "price": { "credits": 4, "usd": "0.04", "charged": false }, "error": { "code": "content_refused", "message": "The model refused this request under its content rules. Your credits came back. Change the prompt or the files before trying again.", "hint": "Change the prompt or the files. Trying the same again can't help, and refusals count toward a pause of the account.", "retryable": false, "docs_url": "https://docs.nocamclub.com/errors/content_refused" } } ``` It has the same `hint` and `retryable` as a refused call. To try again, send the same request with a new `Idempotency-Key`. | Code | Meaning | Worth retrying? | |---|---|---| | [`content_refused`](https://docs.nocamclub.com/errors/content_refused.md) | The model or our check refused it | After a change | | [`bad_input_file`](https://docs.nocamclub.com/errors/bad_input_file.md) | The model couldn't read a file | After a change | | [`unsupported_request`](https://docs.nocamclub.com/errors/unsupported_request.md) | The model can't do this combination | After a change | | [`prompt_too_long`](https://docs.nocamclub.com/errors/prompt_too_long.md) | The prompt is too long | After a change | | [`output_limit`](https://docs.nocamclub.com/errors/output_limit.md) | The answer didn't fit | After a change | | [`timed_out`](https://docs.nocamclub.com/errors/timed_out.md) | The model didn't finish in time | Yes | | [`provider_unavailable`](https://docs.nocamclub.com/errors/provider_unavailable.md) | No route could run it | Yes | | [`generation_failed`](https://docs.nocamclub.com/errors/generation_failed.md) | The generation failed | Yes | | [`sandbox_failure`](https://docs.nocamclub.com/errors/sandbox_failure.md) | The sandbox failed it on request | After a change | | [`canceled`](https://docs.nocamclub.com/errors/canceled.md) | Canceled | After a change | [`input_refused`](https://docs.nocamclub.com/errors/input_refused.md) can also arrive here, when a model refuses one of your files after the start. Retrying a failed generation needs a **new** `Idempotency-Key`: the old one returns the same failure. --- # invalid_request > The request can't be read Source: https://docs.nocamclub.com/errors/invalid_request - **Where:** HTTP 400, and nothing started - **Charged:** No - **Worth retrying:** Not as it is. The request has to change first. ## What happened The body isn't valid JSON, or an Idempotency-Key is over 200 characters. ## What to do Send `application/json`, and keep the key to 200 characters. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "invalid_request", "message": "The body isn't valid JSON, or an Idempotency-Key is over 200 characters.", "hint": "Send `application/json`, and keep the key to 200 characters.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/invalid_request" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # invalid_parameter > A field is wrong Source: https://docs.nocamclub.com/errors/invalid_parameter - **Where:** HTTP 400, and nothing started - **Charged:** No - **Worth retrying:** Not as it is. The request has to change first. ## What happened A field is unknown, missing or has a value this model doesn't take. `path` names the field, and `hint` usually lists the values that work. ## What to do Correct the field named in `path`. Read the model's `input_schema` from `GET /v1/models/{id}` rather than guessing its options. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "invalid_parameter", "message": "A field is unknown, missing or has a value this model doesn't take. `path` names the field, and `hint` usually lists the values that work.", "hint": "Correct the field named in `path`. Read the model's `input_schema` from `GET /v1/models/{id}` rather than guessing its options.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/invalid_parameter" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # unknown_model > That model isn't on sale Source: https://docs.nocamclub.com/errors/unknown_model - **Where:** HTTP 400, and nothing started - **Charged:** No - **Worth retrying:** Not as it is. The request has to change first. ## What happened The model id doesn't exist, or the model isn't sold through the API right now. ## What to do List what's on sale with `GET /v1/models` and use an `id` from it. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "unknown_model", "message": "The model id doesn't exist, or the model isn't sold through the API right now.", "hint": "List what's on sale with `GET /v1/models` and use an `id` from it.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/unknown_model" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # input_refused > Refused by content rules Source: https://docs.nocamclub.com/errors/input_refused - **Where:** HTTP 400, and nothing started - **Charged:** No - **Worth retrying:** Not as it is. The request has to change first. ## What happened The prompt or a file breaks the [content rules](https://docs.nocamclub.com/rules.md). As a 400, it was refused at the door. On a failed generation, the model refused a file: it took it for a real person or a protected work. ## What to do Change the prompt or the file. Don't repeat the same request: refusals count toward a pause of the account. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "input_refused", "message": "The prompt or a file breaks the [content rules](https://docs.nocamclub.com/rules.md). As a 400, it was refused at the door. On a failed generation, the model refused a file: it took it for a real person or a protected work.", "hint": "Change the prompt or the file. Don't repeat the same request: refusals count toward a pause of the account.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/input_refused" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # invalid_api_key > The key isn't valid Source: https://docs.nocamclub.com/errors/invalid_api_key - **Where:** HTTP 401, and nothing started - **Charged:** No - **Worth retrying:** No. Someone has to change the key or the account. ## What happened There's no key in the request, or it's mistyped or revoked. ## What to do Send `Authorization: Bearer nc_live_…`. If the key was revoked, get a new one. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "invalid_api_key", "message": "There's no key in the request, or it's mistyped or revoked.", "hint": "Send `Authorization: Bearer nc_live_…`. If the key was revoked, get a new one.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/invalid_api_key" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # expired_api_key > The key has expired Source: https://docs.nocamclub.com/errors/expired_api_key - **Where:** HTTP 401, and nothing started - **Charged:** No - **Worth retrying:** No. Someone has to change the key or the account. ## What happened This key had an expiry date and it has passed. ## What to do Get a new key. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "expired_api_key", "message": "This key had an expiry date and it has passed.", "hint": "Get a new key.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/expired_api_key" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # insufficient_credits > Not enough credits Source: https://docs.nocamclub.com/errors/insufficient_credits - **Where:** HTTP 402, and nothing started - **Charged:** No - **Worth retrying:** No. Someone has to change the key or the account. ## What happened The balance is below this generation's price. The error carries `credits` (the price) and `balance`. Only paid credits buy models directly: bonus credits are for scenes. ## What to do Top up at the link in `top_up_url`. An agent should send the person there and never top up on its own. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "insufficient_credits", "message": "The balance is below this generation's price. The error carries `credits` (the price) and `balance`. Only paid credits buy models directly: bonus credits are for scenes.", "hint": "Top up at the link in `top_up_url`. An agent should send the person there and never top up on its own.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/insufficient_credits" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # account_suspended > The account is paused Source: https://docs.nocamclub.com/errors/account_suspended - **Where:** HTTP 403, and nothing started - **Charged:** No - **Worth retrying:** No. Someone has to change the key or the account. ## What happened The account can't use the API right now. Twenty refused requests within 24 hours pause it. ## What to do Contact support. Retrying won't help. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "account_suspended", "message": "The account can't use the API right now. Twenty refused requests within 24 hours pause it.", "hint": "Contact support. Retrying won't help.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/account_suspended" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # ip_not_allowed > Not from this address Source: https://docs.nocamclub.com/errors/ip_not_allowed - **Where:** HTTP 403, and nothing started - **Charged:** No - **Worth retrying:** No. Someone has to change the key or the account. ## What happened This key only works from listed addresses. ## What to do Call from a listed address, or use another key. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "ip_not_allowed", "message": "This key only works from listed addresses.", "hint": "Call from a listed address, or use another key.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/ip_not_allowed" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # missing_scope > The key can't do this Source: https://docs.nocamclub.com/errors/missing_scope - **Where:** HTTP 403, and nothing started - **Charged:** No - **Worth retrying:** No. Someone has to change the key or the account. ## What happened The key doesn't have the permission this call needs: `models:read`, `generations:read`, `generations:write`, `uploads:write` or `account:read`. ## What to do Use a key with that permission. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "missing_scope", "message": "The key doesn't have the permission this call needs: `models:read`, `generations:read`, `generations:write`, `uploads:write` or `account:read`.", "hint": "Use a key with that permission.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/missing_scope" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # model_not_allowed > The key can't use this model Source: https://docs.nocamclub.com/errors/model_not_allowed - **Where:** HTTP 403, and nothing started - **Charged:** No - **Worth retrying:** No. Someone has to change the key or the account. ## What happened This key is limited to a list of models. ## What to do Use a model on the key's list, or another key. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "model_not_allowed", "message": "This key is limited to a list of models.", "hint": "Use a model on the key's list, or another key.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/model_not_allowed" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # origin_not_allowed > Not from this page Source: https://docs.nocamclub.com/errors/origin_not_allowed - **Where:** HTTP 403, and nothing started - **Charged:** No - **Worth retrying:** Not as it is. The request has to change first. ## What happened A browser page called the MCP server, and only a few known pages may. ## What to do Call it from a server, or from a client that sends no `Origin`. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "origin_not_allowed", "message": "A browser page called the MCP server, and only a few known pages may.", "hint": "Call it from a server, or from a client that sends no `Origin`.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/origin_not_allowed" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # spend_limit_reached > A spend limit is reached Source: https://docs.nocamclub.com/errors/spend_limit_reached - **Where:** HTTP 403, and nothing started - **Charged:** No - **Worth retrying:** No. Someone has to change the key or the account. ## What happened The key's limit or the account's daily limit would be passed by this price. `limit` and `spent` are in the error when it's the daily one. The daily limit resets at 00:00 UTC. ## What to do Wait for the period to reset, or raise the limit. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "spend_limit_reached", "message": "The key's limit or the account's daily limit would be passed by this price. `limit` and `spent` are in the error when it's the daily one. The daily limit resets at 00:00 UTC.", "hint": "Wait for the period to reset, or raise the limit.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/spend_limit_reached" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # not_found > Not found Source: https://docs.nocamclub.com/errors/not_found - **Where:** HTTP 404, and nothing started - **Charged:** No - **Worth retrying:** Not as it is. The request has to change first. ## What happened There's no such object or path, or it belongs to another account, or to the other mode (`live` and `test` don't see each other). ## What to do Check the id, and that you're using the key that made it. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "not_found", "message": "There's no such object or path, or it belongs to another account, or to the other mode (`live` and `test` don't see each other).", "hint": "Check the id, and that you're using the key that made it.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/not_found" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # idempotency_conflict > This key was used with another request Source: https://docs.nocamclub.com/errors/idempotency_conflict - **Where:** HTTP 409, and nothing started - **Charged:** No - **Worth retrying:** Not as it is. The request has to change first. ## What happened The same `Idempotency-Key` came with a different body. ## What to do Use a new key for a new request. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "idempotency_conflict", "message": "The same `Idempotency-Key` came with a different body.", "hint": "Use a new key for a new request.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/idempotency_conflict" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # no_route > No route can do this right now Source: https://docs.nocamclub.com/errors/no_route - **Where:** HTTP 409, and nothing started - **Charged:** No - **Worth retrying:** Not as it is. The request has to change first. ## What happened The model is on sale, but no route that's on can take these settings or this many files. ## What to do Try other settings or fewer files. Check `prices` in `GET /v1/models/{id}`: it lists what can be made now. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "no_route", "message": "The model is on sale, but no route that's on can take these settings or this many files.", "hint": "Try other settings or fewer files. Check `prices` in `GET /v1/models/{id}`: it lists what can be made now.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/no_route" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # not_cancelable > Too late to cancel Source: https://docs.nocamclub.com/errors/not_cancelable - **Where:** HTTP 409, and nothing started - **Charged:** No - **Worth retrying:** Not as it is. The request has to change first. ## What happened A model already has this task. It will finish and be billed. ## What to do Wait for it with `GET /v1/generations/{id}`. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "not_cancelable", "message": "A model already has this task. It will finish and be billed.", "hint": "Wait for it with `GET /v1/generations/{id}`.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/not_cancelable" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # not_finished > Still in progress Source: https://docs.nocamclub.com/errors/not_finished - **Where:** HTTP 409, and nothing started - **Charged:** No - **Worth retrying:** Yes. The same request can work, after any wait the error names. ## What happened A generation can't be deleted while it's queued or running. ## What to do Cancel it or wait for it to finish, then delete it. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "not_finished", "message": "A generation can't be deleted while it's queued or running.", "hint": "Cancel it or wait for it to finish, then delete it.", "retryable": true, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/not_finished" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # not_for_sale > Not on sale with these settings Source: https://docs.nocamclub.com/errors/not_for_sale - **Where:** HTTP 409, and nothing started - **Charged:** No - **Worth retrying:** Not as it is. The request has to change first. ## What happened This combination of settings has no price right now. ## What to do Pick one from `prices` in `GET /v1/models/{id}`. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "not_for_sale", "message": "This combination of settings has no price right now.", "hint": "Pick one from `prices` in `GET /v1/models/{id}`.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/not_for_sale" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # upload_not_found > The file isn't there yet Source: https://docs.nocamclub.com/errors/upload_not_found - **Where:** HTTP 409, and nothing started - **Charged:** No - **Worth retrying:** Yes. The same request can work, after any wait the error names. ## What happened `/complete` was called before the file reached the upload link. ## What to do `PUT` the file to `upload_url` first, then call `/complete` again. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "upload_not_found", "message": "`/complete` was called before the file reached the upload link.", "hint": "`PUT` the file to `upload_url` first, then call `/complete` again.", "retryable": true, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/upload_not_found" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # file_too_large > The file is too big Source: https://docs.nocamclub.com/errors/file_too_large - **Where:** HTTP 413, and nothing started - **Charged:** No - **Worth retrying:** Not as it is. The request has to change first. ## What happened Photos are limited to 10 MB, videos to 50 MB, audio to 15 MB. A request body is limited to 1 MB, so files never go inside it. ## What to do Send a smaller file, and send files through `/v1/uploads`. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "file_too_large", "message": "Photos are limited to 10 MB, videos to 50 MB, audio to 15 MB. A request body is limited to 1 MB, so files never go inside it.", "hint": "Send a smaller file, and send files through `/v1/uploads`.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/file_too_large" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # unsupported_media > We can't read this file Source: https://docs.nocamclub.com/errors/unsupported_media - **Where:** HTTP 415, and nothing started - **Charged:** No - **Worth retrying:** Not as it is. The request has to change first. ## What happened The file's first bytes decide what it is, not its name or the type you sent. We take PNG, JPEG, WebP, MP4, MOV, MP3 and WAV. ## What to do Convert it to one of these. A web page saved as `.png` is still a web page. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "unsupported_media", "message": "The file's first bytes decide what it is, not its name or the type you sent. We take PNG, JPEG, WebP, MP4, MOV, MP3 and WAV.", "hint": "Convert it to one of these. A web page saved as `.png` is still a web page.", "retryable": false, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/unsupported_media" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # rate_limited > Too many requests Source: https://docs.nocamclub.com/errors/rate_limited - **Where:** HTTP 429, and nothing started - **Charged:** No - **Worth retrying:** Yes. The same request can work, after any wait the error names. ## What happened Past a per-minute limit. `Retry-After` says how many seconds to wait, and `limit` is in the error. ## What to do Wait for `Retry-After`, then send the same request. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "rate_limited", "message": "Past a per-minute limit. `Retry-After` says how many seconds to wait, and `limit` is in the error.", "hint": "Wait for `Retry-After`, then send the same request.", "retryable": true, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/rate_limited" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # too_many_active > Too many in progress Source: https://docs.nocamclub.com/errors/too_many_active - **Where:** HTTP 429, and nothing started - **Charged:** No - **Worth retrying:** Yes. The same request can work, after any wait the error names. ## What happened This account has as many generations in progress as its level allows. `limit` is in the error. ## What to do Wait for one to finish, then send it again. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "too_many_active", "message": "This account has as many generations in progress as its level allows. `limit` is in the error.", "hint": "Wait for one to finish, then send it again.", "retryable": true, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/too_many_active" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # internal > Something went wrong on our side Source: https://docs.nocamclub.com/errors/internal - **Where:** HTTP 500, and nothing started - **Charged:** No - **Worth retrying:** Yes. The same request can work, after any wait the error names. ## What happened An unexpected error. Nothing is lost if you retry with the same `Idempotency-Key`. ## What to do Retry with the same `Idempotency-Key` after a few seconds, so it can't run twice. Quote `request_id` if it keeps happening. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "internal", "message": "An unexpected error. Nothing is lost if you retry with the same `Idempotency-Key`.", "hint": "Retry with the same `Idempotency-Key` after a few seconds, so it can't run twice. Quote `request_id` if it keeps happening.", "retryable": true, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/internal" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # platform_paused > The API is paused Source: https://docs.nocamclub.com/errors/platform_paused - **Where:** HTTP 503, and nothing started - **Charged:** No - **Worth retrying:** Yes. The same request can work, after any wait the error names. ## What happened We've switched the API or MCP off for a while. ## What to do Try again later. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "error": { "code": "platform_paused", "message": "We've switched the API or MCP off for a while.", "hint": "Try again later.", "retryable": true, "request_id": "req_01a1b37b65dc7dcd8c060f296add5cf8", "docs_url": "https://docs.nocamclub.com/errors/platform_paused" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # content_refused > The model or our check refused it Source: https://docs.nocamclub.com/errors/content_refused - **Where:** `error` of a generation with `status: "failed"` - **Charged:** No - **Worth retrying:** Not as it is. The request has to change first. ## What happened The content check, or the model itself, refused this request. The credits came back. ## What to do Change the prompt or the files. Trying the same again can't help, and refusals count toward a pause of the account. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "status": "failed", "error": { "code": "content_refused", "message": "The content check, or the model itself, refused this request. The credits came back.", "hint": "Change the prompt or the files. Trying the same again can't help, and refusals count toward a pause of the account.", "retryable": false, "docs_url": "https://docs.nocamclub.com/errors/content_refused" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # bad_input_file > The model couldn't read a file Source: https://docs.nocamclub.com/errors/bad_input_file - **Where:** `error` of a generation with `status: "failed"` - **Charged:** No - **Worth retrying:** Not as it is. The request has to change first. ## What happened A file was accepted but the model couldn't open it. The credits came back. ## What to do Check that the file opens and isn't damaged, or upload it again. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "status": "failed", "error": { "code": "bad_input_file", "message": "A file was accepted but the model couldn't open it. The credits came back.", "hint": "Check that the file opens and isn't damaged, or upload it again.", "retryable": false, "docs_url": "https://docs.nocamclub.com/errors/bad_input_file" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # unsupported_request > The model can't do this combination Source: https://docs.nocamclub.com/errors/unsupported_request - **Where:** `error` of a generation with `status: "failed"` - **Charged:** No - **Worth retrying:** Not as it is. The request has to change first. ## What happened Every route refused these settings and files together. The credits came back. ## What to do Check the limits in `GET /v1/models/{id}` and change the settings or the files. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "status": "failed", "error": { "code": "unsupported_request", "message": "Every route refused these settings and files together. The credits came back.", "hint": "Check the limits in `GET /v1/models/{id}` and change the settings or the files.", "retryable": false, "docs_url": "https://docs.nocamclub.com/errors/unsupported_request" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # prompt_too_long > The prompt is too long Source: https://docs.nocamclub.com/errors/prompt_too_long - **Where:** `error` of a generation with `status: "failed"` - **Charged:** No - **Worth retrying:** Not as it is. The request has to change first. ## What happened The prompt passed our limit of 10,000 characters but was too long for this model. The credits came back. ## What to do Shorten the prompt. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "status": "failed", "error": { "code": "prompt_too_long", "message": "The prompt passed our limit of 10,000 characters but was too long for this model. The credits came back.", "hint": "Shorten the prompt.", "retryable": false, "docs_url": "https://docs.nocamclub.com/errors/prompt_too_long" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # output_limit > The answer didn't fit Source: https://docs.nocamclub.com/errors/output_limit - **Where:** `error` of a generation with `status: "failed"` - **Charged:** No - **Worth retrying:** Not as it is. The request has to change first. ## What happened A text model ran out of room before it could answer. The credits came back. ## What to do Ask for a shorter answer. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "status": "failed", "error": { "code": "output_limit", "message": "A text model ran out of room before it could answer. The credits came back.", "hint": "Ask for a shorter answer.", "retryable": false, "docs_url": "https://docs.nocamclub.com/errors/output_limit" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # timed_out > The model didn't finish in time Source: https://docs.nocamclub.com/errors/timed_out - **Where:** `error` of a generation with `status: "failed"` - **Charged:** No - **Worth retrying:** Yes. The same request can work, after any wait the error names. ## What happened We stopped waiting and the credits came back. We keep checking for a day: if the result arrives, the generation turns to `succeeded` with `recovered: true`, free of charge. ## What to do Check the generation again later before ordering another. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "status": "failed", "error": { "code": "timed_out", "message": "We stopped waiting and the credits came back. We keep checking for a day: if the result arrives, the generation turns to `succeeded` with `recovered: true`, free of charge.", "hint": "Check the generation again later before ordering another.", "retryable": true, "docs_url": "https://docs.nocamclub.com/errors/timed_out" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # provider_unavailable > No route could run it Source: https://docs.nocamclub.com/errors/provider_unavailable - **Where:** `error` of a generation with `status: "failed"` - **Charged:** No - **Worth retrying:** Yes. The same request can work, after any wait the error names. ## What happened Every route was busy, down or unable to take it. The credits came back. ## What to do Try the same request in a few minutes, or another model. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "status": "failed", "error": { "code": "provider_unavailable", "message": "Every route was busy, down or unable to take it. The credits came back.", "hint": "Try the same request in a few minutes, or another model.", "retryable": true, "docs_url": "https://docs.nocamclub.com/errors/provider_unavailable" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # generation_failed > The generation failed Source: https://docs.nocamclub.com/errors/generation_failed - **Where:** `error` of a generation with `status: "failed"` - **Charged:** No - **Worth retrying:** Yes. The same request can work, after any wait the error names. ## What happened The model failed and every other route was tried. The credits came back. ## What to do Try the same request again. If it fails each time, simplify the prompt or try another model. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "status": "failed", "error": { "code": "generation_failed", "message": "The model failed and every other route was tried. The credits came back.", "hint": "Try the same request again. If it fails each time, simplify the prompt or try another model.", "retryable": true, "docs_url": "https://docs.nocamclub.com/errors/generation_failed" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # sandbox_failure > The sandbox failed it on request Source: https://docs.nocamclub.com/errors/sandbox_failure - **Where:** `error` of a generation with `status: "failed"` - **Charged:** No - **Worth retrying:** Not as it is. The request has to change first. ## What happened A test key's prompt had the word `fail`, so the sandbox failed it, to let you test your error handling. ## What to do Take the word fail out of the prompt to get a sample result. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "status": "failed", "error": { "code": "sandbox_failure", "message": "A test key's prompt had the word `fail`, so the sandbox failed it, to let you test your error handling.", "hint": "Take the word fail out of the prompt to get a sample result.", "retryable": false, "docs_url": "https://docs.nocamclub.com/errors/sandbox_failure" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # canceled > Canceled Source: https://docs.nocamclub.com/errors/canceled - **Where:** `error` of a generation with `status: "failed"` - **Charged:** No - **Worth retrying:** Not as it is. The request has to change first. ## What happened This generation was canceled and the credits came back. ## What to do Nothing to do. ## What it looks like The real `message` and `hint` name the details of your request, such as the field and the values that work. ```json { "status": "failed", "error": { "code": "canceled", "message": "This generation was canceled and the credits came back.", "hint": "Nothing to do.", "retryable": false, "docs_url": "https://docs.nocamclub.com/errors/canceled" } } ``` All codes: [Errors](https://docs.nocamclub.com/errors.md). --- # Connect through MCP > Give Claude Code, Cursor and other agents the whole API as tools. Source: https://docs.nocamclub.com/mcp ![A purple character plugs a glowing cable into a small white robot. Made with this API.](https://docs.nocamclub.com/examples/mcp-banner.jpg) The MCP server gives an AI agent the API as tools, with the same key, balance and rules. ```text https://mcp.nocamclub.com/mcp ``` It speaks Streamable HTTP and signs you in with your API key. Use a separate key with a spend limit for each agent, so a mistake has a ceiling: see [Authentication](https://docs.nocamclub.com/authentication.md). Try it with a `nc_test_…` key first: it spends nothing. ## Claude Code ```bash claude mcp add --transport http nocam https://mcp.nocamclub.com/mcp \ --header "Authorization: Bearer $NOCAM_API_KEY" ``` ## Cursor In `~/.cursor/mcp.json`: ```json { "mcpServers": { "nocam": { "url": "https://mcp.nocamclub.com/mcp", "headers": { "Authorization": "Bearer ${env:NOCAM_API_KEY}" } } } } ``` ## VS Code In `.vscode/mcp.json`: ```json { "servers": { "nocam": { "type": "http", "url": "https://mcp.nocamclub.com/mcp", "headers": { "Authorization": "Bearer ${env:NOCAM_API_KEY}" } } } } ``` ## Windsurf In `~/.codeium/windsurf/mcp_config.json`: ```json { "mcpServers": { "nocam": { "serverUrl": "https://mcp.nocamclub.com/mcp", "headers": { "Authorization": "Bearer ${env:NOCAM_API_KEY}" } } } } ``` ## Other clients Point it at the address above and send `Authorization: Bearer `. **claude.ai and ChatGPT** sign in with OAuth rather than a key, and that isn't available yet. ## Try it Ask your agent: > Check my NoCam balance, then make a photo of a red bicycle against a white wall with the cheapest model on sale, and show me the link. ## How the tools behave - **Photos and text come back in the answer**, usually. The tool waits up to 60 seconds. - **Videos return at once** with an `id`, because they take minutes. The agent checks with `get_generation`, and shouldn't call `generate` again. - **Results are links.** A `resource_link` comes along with the JSON. - **Repeating a call doesn't pay twice.** The same `generate` within 10 minutes returns the same generation, unless that one failed or was deleted. `run_again: true` makes another on purpose. - **Problems come back as a result the model can read**, with the same `code`, `hint` and `docs_url` as REST, so the agent can fix them itself. - **Local files.** `upload_media` takes an address or base64 up to 4 MB. For bigger files, `create_upload` gives a ready `curl` command. All tools: [Tools](https://docs.nocamclub.com/mcp/tools.md). How to behave: [For AI agents](https://docs.nocamclub.com/for-ai-agents.md). --- # MCP tools > Every tool the MCP server gives an agent. Source: https://docs.nocamclub.com/mcp/tools Every tool here has the same money, limits and rules as REST. See [Connect through MCP](https://docs.nocamclub.com/mcp.md) for how to set it up. ## list_models Lists the models on sale: what each costs in credits (1 credit = $0.01), how long it usually takes and how often it succeeds. Read-only. | Field | Takes | What it is | |---|---|---| | `kind` | `image`, `video`, `text` | Only this kind of model. | ## get_model A model's options and prices. Use it before generate: the options differ from model to model. Read-only. | Field | Takes | What it is | |---|---|---| | `model` (required) | string | The model id from list_models. | ## estimate_cost Checks the options and says what a generation would cost. Nothing runs and nothing is charged. Read-only. | Field | Takes | What it is | |---|---|---| | `model` (required) | string | The model id from list_models. | | `prompt` (required) | string | What to make. Refer to files by order: img1, img2, video1, audio1. | | `images` | array | Photos: file ids from upload_media or create_upload, or public https addresses. | | `videos` | array | Videos, the same way. | | `audios` | array | Audio, the same way. | | `aspect_ratio` | string | | | `resolution` | string | | | `quality` | string | | | `duration` | integer | Clip length in seconds. | | `reference_mode` | `frames`, `ingredients`, `start` | | | `output_format` | `png`, `jpeg` | | ## generate Makes a photo, a video or text and spends credits. Photos and text are usually back in the answer; videos take minutes, so this returns an id to check with get_generation. Never call it again to check progress. Changes something. | Field | Takes | What it is | |---|---|---| | `model` (required) | string | The model id from list_models. | | `prompt` (required) | string | What to make. Refer to files by order: img1, img2, video1, audio1. | | `images` | array | Photos: file ids from upload_media or create_upload, or public https addresses. | | `videos` | array | Videos, the same way. | | `audios` | array | Audio, the same way. | | `aspect_ratio` | string | | | `resolution` | string | | | `quality` | string | | | `duration` | integer | Clip length in seconds. | | `reference_mode` | `frames`, `ingredients`, `start` | | | `output_format` | `png`, `jpeg` | | | `run_again` | boolean | Make another one from exactly the same request. Without it, the same request within 10 minutes returns the same generation, unless that one failed or was deleted. | ## get_generation Status and result of a generation. Use it to check on one that was still working. Read-only. | Field | Takes | What it is | |---|---|---| | `id` (required) | string | The id from generate. | ## list_generations Earlier generations, newest first, to find a result or use it as a file in a new one. Read-only. | Field | Takes | What it is | |---|---|---| | `status` | `queued`, `running`, `succeeded`, `failed`, `canceled` | | | `model` | string | | | `cursor` | string | | | `limit` | integer | | ## cancel_generation Cancels a generation still in the queue and gives the credits back. Once a model has it, it finishes and is billed. Changes or removes something. | Field | Takes | What it is | |---|---|---| | `id` (required) | string | | ## delete_generation Removes a finished generation's files and prompt now, without waiting for them to expire. Changes or removes something. | Field | Takes | What it is | |---|---|---| | `id` (required) | string | | ## upload_media Puts a photo, video or audio file into storage from a public https address, or from base64 up to 4 MB, and returns a file id for generate. Use only files you have the right to use. Changes something. | Field | Takes | What it is | |---|---|---| | `url` | string | A public https address. | | `data_base64` | string | The file itself, base64, up to 4 MB. | ## create_upload A link to PUT a local file to, for agents that can run commands. Returns a ready curl command; the file id works in generate once the file is there. Changes something. | Field | Takes | What it is | |---|---|---| | `content_type` (required) | string | image/png, image/jpeg, image/webp, video/mp4, video/quicktime, audio/mpeg or audio/wav. | | `bytes` (required) | integer | The file's size. | ## get_account The balance, the limits of this connection and where to top up. Never top up on your own: send the person to the link. Read-only. No fields. --- # Choose a model > Which model for which job, and every model on sale. Source: https://docs.nocamclub.com/models ## By the job | The job | Model | |---|---| | A photo from one photo, cheap and good | [`nano-banana-2`](https://docs.nocamclub.com/models/nano-banana-2.md) | | The same subject across many photos | [`nano-banana-pro`](https://docs.nocamclub.com/models/nano-banana-pro.md) | | Exact words in a photo: posters, signs, covers | [`gpt-image-2`](https://docs.nocamclub.com/models/gpt-image-2.md) | | A clean portrait or avatar | [`gpt-image-2.5-flare`](https://docs.nocamclub.com/models/gpt-image-2.5-flare.md) | | A sticker, an icon, something graphic | [`gpt-image-2.5-sunburst`](https://docs.nocamclub.com/models/gpt-image-2.5-sunburst.md) | | Many reference photos, cheap | [`seedream-5.0-flash`](https://docs.nocamclub.com/models/seedream-5.0-flash.md) | | A photo from text, as cheap as it gets | [`grok-imagine`](https://docs.nocamclub.com/models/grok-imagine.md) | | A talking clip from one photo, nearly free | [`muse-video`](https://docs.nocamclub.com/models/muse-video.md) | | A short clip from text or photos, or editing a clip you have | [`omni-flash`](https://docs.nocamclub.com/models/omni-flash.md) | | The best clip: long, 1080p, or with video and audio references | [`seedance-2.5`](https://docs.nocamclub.com/models/seedance-2.5.md) | | A good clip up to 15 s, for less | [`seedance-2.0-fast`](https://docs.nocamclub.com/models/seedance-2.0-fast.md) | | A text answer, quick and cheap | [`gpt-6-luna`](https://docs.nocamclub.com/models/gpt-6-luna.md) | | A text answer that takes real thought | [`claude-opus-5.5`](https://docs.nocamclub.com/models/claude-opus-5.5.md) | ## All of them As of 2026-11-07. The list changes, so check `GET /v1/models` before you rely on it. "From" is the lowest price in credits. The last three columns are how many files of each kind it takes. | Model | Id | Makes | From | Photos | Videos | Audio | |---|---|---|---|---|---|---| | [Nano Banana 2](https://docs.nocamclub.com/models/nano-banana-2.md) | `nano-banana-2` | Photo | 5 | 5 | 0 | 0 | | [Nano Banana Pro](https://docs.nocamclub.com/models/nano-banana-pro.md) | `nano-banana-pro` | Photo | 5 | 5 | 0 | 0 | | [GPT Image 2.5 Flare](https://docs.nocamclub.com/models/gpt-image-2.5-flare.md) | `gpt-image-2.5-flare` | Photo | 4 | 8 | 0 | 0 | | [GPT Image 2](https://docs.nocamclub.com/models/gpt-image-2.md) | `gpt-image-2` | Photo | 4 | 5 | 0 | 0 | | [Muse Video](https://docs.nocamclub.com/models/muse-video.md) | `muse-video` | Video | 2 | 1 | 0 | 0 | | [GPT Image 2.5 Sunburst](https://docs.nocamclub.com/models/gpt-image-2.5-sunburst.md) | `gpt-image-2.5-sunburst` | Photo | 4 | 8 | 0 | 0 | | [Grok Imagine](https://docs.nocamclub.com/models/grok-imagine.md) | `grok-imagine` | Photo | 2 | 0 | 0 | 0 | | [Grok Imagine Quality](https://docs.nocamclub.com/models/grok-imagine-quality.md) | `grok-imagine-quality` | Photo | 3 | 8 | 0 | 0 | | [Seedream 5.0 Flash](https://docs.nocamclub.com/models/seedream-5.0-flash.md) | `seedream-5.0-flash` | Photo | 5 | 10 | 0 | 0 | | [Seedream 5.0 Pro](https://docs.nocamclub.com/models/seedream-5.0-pro.md) | `seedream-5.0-pro` | Photo | 11 | 10 | 0 | 0 | | [Omni Flash](https://docs.nocamclub.com/models/omni-flash.md) | `omni-flash` | Video | 12 | 3 | 1 | 0 | | [Seedance 2.0 Fast](https://docs.nocamclub.com/models/seedance-2.0-fast.md) | `seedance-2.0-fast` | Video | 18 | 9 | 3 | 3 | | [Seedance 2.5](https://docs.nocamclub.com/models/seedance-2.5.md) | `seedance-2.5` | Video | 30 | 30 | 10 | 10 | | [GPT-6 Luna](https://docs.nocamclub.com/models/gpt-6-luna.md) | `gpt-6-luna` | Text | 1 | 4 | 0 | 0 | | [Claude Opus 5.5](https://docs.nocamclub.com/models/claude-opus-5.5.md) | `claude-opus-5.5` | Text | 10 | 4 | 0 | 0 | ## Reading a model page Each page has what the model is good at, how to write prompts for it, a real result where we have one, its options and its prices. Its options and prices come straight from the catalog. --- # Nano Banana 2 > A strong all-rounder for photos, from text or from your own photos. Fast and cheap, up to 4K. Source: https://docs.nocamclub.com/models/nano-banana-2 - **Model id:** `nano-banana-2` - **Makes:** photos - **From:** 5 credits ($0.05) - **Routes:** 2 ## Writing prompts - Say what to keep from the photo, then what's new: "Keep the face and hair of img1. The same person on a rooftop at sunset." - Name the camera and the feel: "phone photo", "polished 3D render", "shallow depth of field". - Ask for room in the frame if you'll put text over it: "empty dark space on the right". ## A real result: A header for these docs ![A purple character types on a laptop in a dark room lit by neon, with windows of code floating behind him.](https://docs.nocamclub.com/examples/docs-hero.jpg) Made through this API: 5504×3072, 6 credits, 47 seconds, from [this photo](https://docs.nocamclub.com/examples/mascot.jpg). The call below is the one that made it. ## Call it **cURL** ```bash # A new Idempotency-Key for each new thing you want made, the same one when you retry it. curl https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Prefer: wait=60" \ -H "Idempotency-Key: nano-banana-2-$(date +%s)" \ -d '{ "model": "nano-banana-2", "input": { "prompt": "Keep the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers. He sits at a desk in a dark room and types on a laptop. The room is lit by purple and lime green neon. Rounded windows with lines of code float in the air behind him. Polished 3D render, shallow depth of field, empty dark space on the right side of the frame. No words or letters anywhere.", "resolution": "4K", "aspect_ratio": "16:9", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }' ``` **JavaScript** ```js const res = await fetch("https://api.nocamclub.com/v1/generations", { method: "POST", headers: { Authorization: `Bearer ${process.env.NOCAM_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID(), Prefer: "wait=60", }, body: JSON.stringify({ "model": "nano-banana-2", "input": { "prompt": "Keep the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers. He sits at a desk in a dark room and types on a laptop. The room is lit by purple and lime green neon. Rounded windows with lines of code float in the air behind him. Polished 3D render, shallow depth of field, empty dark space on the right side of the frame. No words or letters anywhere.", "resolution": "4K", "aspect_ratio": "16:9", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }), }); const generation = await res.json(); ``` **Python** ```python import os, uuid, requests res = requests.post( "https://api.nocamclub.com/v1/generations", headers={"Authorization": f"Bearer {os.environ['NOCAM_API_KEY']}", "Prefer": "wait=60", "Idempotency-Key": str(uuid.uuid4())}, json={ "model": "nano-banana-2", "input": { "prompt": "Keep the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers. He sits at a desk in a dark room and types on a laptop. The room is lit by purple and lime green neon. Rounded windows with lines of code float in the air behind him. Polished 3D render, shallow depth of field, empty dark space on the right side of the frame. No words or letters anywhere.", "resolution": "4K", "aspect_ratio": "16:9", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }, timeout=90, ) generation = res.json() ``` **MCP tool** ```json { "name": "generate", "arguments": { "model": "nano-banana-2", "prompt": "Keep the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers. He sits at a desk in a dark room and types on a laptop. The room is lit by purple and lime green neon. Rounded windows with lines of code float in the air behind him. Polished 3D render, shallow depth of field, empty dark space on the right side of the frame. No words or letters anywhere.", "resolution": "4K", "aspect_ratio": "16:9", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } } ``` ## Options | Field | Takes | Default | What it is | |---|---|---|---| | `prompt` (required) | Up to 10000 characters | | What to make. Refer to files by order: img1, img2, video1, audio1. | | `aspect_ratio` | `1:1`, `16:9`, `9:16`, `4:3`, `3:4` | `1:1` | | | `resolution` | `1K`, `2K`, `4K` | `1K` | | | `output_format` | `png`, `jpeg` | | | | `images` | Up to 5 | | Photos: file ids from /v1/uploads, or https addresses. | Any other field is refused. How files work: [Uploads](https://docs.nocamclub.com/api/uploads.md) and [Files in prompts](https://docs.nocamclub.com/api/files-in-prompts.md). ## Prices In credits (1 credit = $0.01), as of 2026-11-07. For the current list: `GET /v1/models/nano-banana-2`. | Size | Credits | |---|---| | 1K | 5 | | 2K | 5 | | 4K | 6 | --- # Nano Banana Pro > The same subject from different angles and in different places. Our choice for keeping a look across a series. Source: https://docs.nocamclub.com/models/nano-banana-pro - **Model id:** `nano-banana-pro` - **Makes:** photos - **From:** 5 credits ($0.05) - **Routes:** 2 ## Writing prompts - Repeat the same description of the subject, word for word, in every prompt of a series. - Make each frame from the original photo, not from the previous result. - See [the same character across many photos](https://docs.nocamclub.com/guides/same-character.md). ## A real result: A banner for the MCP page ![A purple character plugs a glowing lime green cable into a small white robot, whose eyes light up.](https://docs.nocamclub.com/examples/mcp-banner.jpg) Made through this API: 2752×1536, 5 credits, 41 seconds, from [this photo](https://docs.nocamclub.com/examples/mascot.jpg). The call below is the one that made it. ## Call it **cURL** ```bash # A new Idempotency-Key for each new thing you want made, the same one when you retry it. curl https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Prefer: wait=60" \ -H "Idempotency-Key: nano-banana-pro-$(date +%s)" \ -d '{ "model": "nano-banana-pro", "input": { "prompt": "Keep the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers. He plugs a glowing lime green cable into the back of a small friendly white robot, and the robot'\''s eyes light up. Dark studio, purple rim light, polished 3D render. No words or letters anywhere.", "resolution": "2K", "aspect_ratio": "16:9", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }' ``` **JavaScript** ```js const res = await fetch("https://api.nocamclub.com/v1/generations", { method: "POST", headers: { Authorization: `Bearer ${process.env.NOCAM_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID(), Prefer: "wait=60", }, body: JSON.stringify({ "model": "nano-banana-pro", "input": { "prompt": "Keep the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers. He plugs a glowing lime green cable into the back of a small friendly white robot, and the robot's eyes light up. Dark studio, purple rim light, polished 3D render. No words or letters anywhere.", "resolution": "2K", "aspect_ratio": "16:9", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }), }); const generation = await res.json(); ``` **Python** ```python import os, uuid, requests res = requests.post( "https://api.nocamclub.com/v1/generations", headers={"Authorization": f"Bearer {os.environ['NOCAM_API_KEY']}", "Prefer": "wait=60", "Idempotency-Key": str(uuid.uuid4())}, json={ "model": "nano-banana-pro", "input": { "prompt": "Keep the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers. He plugs a glowing lime green cable into the back of a small friendly white robot, and the robot's eyes light up. Dark studio, purple rim light, polished 3D render. No words or letters anywhere.", "resolution": "2K", "aspect_ratio": "16:9", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }, timeout=90, ) generation = res.json() ``` **MCP tool** ```json { "name": "generate", "arguments": { "model": "nano-banana-pro", "prompt": "Keep the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers. He plugs a glowing lime green cable into the back of a small friendly white robot, and the robot's eyes light up. Dark studio, purple rim light, polished 3D render. No words or letters anywhere.", "resolution": "2K", "aspect_ratio": "16:9", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } } ``` ## Options | Field | Takes | Default | What it is | |---|---|---|---| | `prompt` (required) | Up to 10000 characters | | What to make. Refer to files by order: img1, img2, video1, audio1. | | `aspect_ratio` | `1:1`, `16:9`, `9:16`, `4:3`, `3:4` | `1:1` | | | `resolution` | `1K`, `2K`, `4K` | `1K` | | | `output_format` | `png`, `jpeg` | | | | `images` | Up to 5 | | Photos: file ids from /v1/uploads, or https addresses. | Any other field is refused. How files work: [Uploads](https://docs.nocamclub.com/api/uploads.md) and [Files in prompts](https://docs.nocamclub.com/api/files-in-prompts.md). ## Prices In credits (1 credit = $0.01), as of 2026-11-07. For the current list: `GET /v1/models/nano-banana-pro`. | Size | Credits | |---|---| | 1K | 5 | | 2K | 5 | | 4K | 7 | --- # GPT Image 2.5 Flare > Portraits and clean compositions from your photos. Takes more photos at once than GPT Image 2. Source: https://docs.nocamclub.com/models/gpt-image-2.5-flare - **Model id:** `gpt-image-2.5-flare` - **Makes:** photos - **From:** 4 credits ($0.04) - **Routes:** 2 ## Writing prompts - It's among the stricter models about clothing: a fashion prompt that passes elsewhere may be refused here. If so, try another model rather than rewording. - A flat, plain background is a good way to get something you can cut out. ## A real result: An avatar ![A head and shoulders portrait of the purple character on a flat lime green background.](https://docs.nocamclub.com/examples/avatar.jpg) Made through this API: 1024×1024, 4 credits, 44 seconds, from [this photo](https://docs.nocamclub.com/examples/mascot.jpg). The call below is the one that made it. ## Call it **cURL** ```bash # A new Idempotency-Key for each new thing you want made, the same one when you retry it. curl https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Prefer: wait=60" \ -H "Idempotency-Key: gpt-image-2.5-flare-$(date +%s)" \ -d '{ "model": "gpt-image-2.5-flare", "input": { "prompt": "A head and shoulders portrait of the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers, grinning at the camera, centered, on a flat solid lime green background. Polished 3D render. No words or letters.", "resolution": "1K", "quality": "medium", "aspect_ratio": "1:1", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }' ``` **JavaScript** ```js const res = await fetch("https://api.nocamclub.com/v1/generations", { method: "POST", headers: { Authorization: `Bearer ${process.env.NOCAM_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID(), Prefer: "wait=60", }, body: JSON.stringify({ "model": "gpt-image-2.5-flare", "input": { "prompt": "A head and shoulders portrait of the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers, grinning at the camera, centered, on a flat solid lime green background. Polished 3D render. No words or letters.", "resolution": "1K", "quality": "medium", "aspect_ratio": "1:1", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }), }); const generation = await res.json(); ``` **Python** ```python import os, uuid, requests res = requests.post( "https://api.nocamclub.com/v1/generations", headers={"Authorization": f"Bearer {os.environ['NOCAM_API_KEY']}", "Prefer": "wait=60", "Idempotency-Key": str(uuid.uuid4())}, json={ "model": "gpt-image-2.5-flare", "input": { "prompt": "A head and shoulders portrait of the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers, grinning at the camera, centered, on a flat solid lime green background. Polished 3D render. No words or letters.", "resolution": "1K", "quality": "medium", "aspect_ratio": "1:1", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }, timeout=90, ) generation = res.json() ``` **MCP tool** ```json { "name": "generate", "arguments": { "model": "gpt-image-2.5-flare", "prompt": "A head and shoulders portrait of the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers, grinning at the camera, centered, on a flat solid lime green background. Polished 3D render. No words or letters.", "resolution": "1K", "quality": "medium", "aspect_ratio": "1:1", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } } ``` ## Options | Field | Takes | Default | What it is | |---|---|---|---| | `prompt` (required) | Up to 10000 characters | | What to make. Refer to files by order: img1, img2, video1, audio1. | | `aspect_ratio` | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3` | `1:1` | | | `resolution` | `1K`, `2K`, `4K` | `1K` | | | `quality` | `low`, `medium`, `high` | `medium` | | | `output_format` | `png`, `jpeg` | | | | `images` | Up to 8 | | Photos: file ids from /v1/uploads, or https addresses. | Any other field is refused. How files work: [Uploads](https://docs.nocamclub.com/api/uploads.md) and [Files in prompts](https://docs.nocamclub.com/api/files-in-prompts.md). ## Prices In credits (1 credit = $0.01), as of 2026-11-07. For the current list: `GET /v1/models/gpt-image-2.5-flare`. | Size | low | medium | high | |---|---|---|---| | 1K | 4 | 4 | 4 | | 2K | — | 9 | — | | 4K | — | 15 | — | --- # GPT Image 2 > Anything with exact words on it: posters, signs, covers. Also strong from text alone. Source: https://docs.nocamclub.com/models/gpt-image-2 - **Model id:** `gpt-image-2` - **Makes:** photos - **From:** 4 credits ($0.04) - **Routes:** 2 ## Writing prompts - Write the words exactly, say where they go, and add "the spelling must be exact". - Say what shouldn't be there as well: "no words, letters, logos or people" gives you a clean background. - At 2K and 4K it's sold in medium quality only. Check `prices`. ## A real result: A poster with real words ![A street poster: the purple character holds up a glowing lime key under the headline ONE KEY. EVERY MODEL. and the words NoCam API.](https://docs.nocamclub.com/examples/poster.jpg) Made through this API: 768×1024, 4 credits, 40 seconds, from [this photo](https://docs.nocamclub.com/examples/mascot.jpg). The call below is the one that made it. ## Call it **cURL** ```bash # A new Idempotency-Key for each new thing you want made, the same one when you retry it. curl https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Prefer: wait=60" \ -H "Idempotency-Key: gpt-image-2-$(date +%s)" \ -d '{ "model": "gpt-image-2", "input": { "prompt": "A bold street poster. the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers holds up a big glowing lime green key. Black background with spray paint texture. At the top, the large headline in white block letters: ONE KEY. EVERY MODEL. At the bottom, smaller lime green letters: NoCam API. The spelling must be exact.", "resolution": "1K", "quality": "medium", "aspect_ratio": "3:4", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }' ``` **JavaScript** ```js const res = await fetch("https://api.nocamclub.com/v1/generations", { method: "POST", headers: { Authorization: `Bearer ${process.env.NOCAM_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID(), Prefer: "wait=60", }, body: JSON.stringify({ "model": "gpt-image-2", "input": { "prompt": "A bold street poster. the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers holds up a big glowing lime green key. Black background with spray paint texture. At the top, the large headline in white block letters: ONE KEY. EVERY MODEL. At the bottom, smaller lime green letters: NoCam API. The spelling must be exact.", "resolution": "1K", "quality": "medium", "aspect_ratio": "3:4", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }), }); const generation = await res.json(); ``` **Python** ```python import os, uuid, requests res = requests.post( "https://api.nocamclub.com/v1/generations", headers={"Authorization": f"Bearer {os.environ['NOCAM_API_KEY']}", "Prefer": "wait=60", "Idempotency-Key": str(uuid.uuid4())}, json={ "model": "gpt-image-2", "input": { "prompt": "A bold street poster. the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers holds up a big glowing lime green key. Black background with spray paint texture. At the top, the large headline in white block letters: ONE KEY. EVERY MODEL. At the bottom, smaller lime green letters: NoCam API. The spelling must be exact.", "resolution": "1K", "quality": "medium", "aspect_ratio": "3:4", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }, timeout=90, ) generation = res.json() ``` **MCP tool** ```json { "name": "generate", "arguments": { "model": "gpt-image-2", "prompt": "A bold street poster. the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers holds up a big glowing lime green key. Black background with spray paint texture. At the top, the large headline in white block letters: ONE KEY. EVERY MODEL. At the bottom, smaller lime green letters: NoCam API. The spelling must be exact.", "resolution": "1K", "quality": "medium", "aspect_ratio": "3:4", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } } ``` ## Options | Field | Takes | Default | What it is | |---|---|---|---| | `prompt` (required) | Up to 10000 characters | | What to make. Refer to files by order: img1, img2, video1, audio1. | | `aspect_ratio` | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3`, `21:9` | `1:1` | | | `resolution` | `1K`, `2K`, `4K` | `1K` | | | `quality` | `low`, `medium`, `high` | `medium` | | | `output_format` | `png`, `jpeg` | | | | `images` | Up to 5 | | Photos: file ids from /v1/uploads, or https addresses. | Any other field is refused. How files work: [Uploads](https://docs.nocamclub.com/api/uploads.md) and [Files in prompts](https://docs.nocamclub.com/api/files-in-prompts.md). ## Prices In credits (1 credit = $0.01), as of 2026-11-07. For the current list: `GET /v1/models/gpt-image-2`. | Size | low | medium | high | |---|---|---|---| | 1K | 4 | 4 | 4 | | 2K | — | 8 | — | | 4K | — | 12 | — | --- # Muse Video > A talking clip from one photo, nearly free. Always 10 seconds, always with sound. Source: https://docs.nocamclub.com/models/muse-video - **Model id:** `muse-video` - **Makes:** videos - **From:** 2 credits ($0.02) - **Routes:** 1, so if it's down the model is down ## Writing prompts - **Put speech in quotes**, and keep it to about 20 words: it has to fit in 10 seconds. - One simple action and a still camera: "He stays in the same place, and the camera doesn't move." - With a photo, the clip takes the photo's shape: `aspect_ratio` is dropped, and `params` comes back without it. Crop the photo to the shape you want. - Keep the frame simple: one subject, face in view. ## Good to know - **There's no length to choose.** Sending `duration` is refused. - Small details can drift: in the clip below the yellow sunglasses came out dark purple. - Its word filter is its own, and a refusal can take a while to arrive. Only a finished clip means it passed. - It has one route, so `no_fallback` is true. ## A real result: The character says our line [Watch the clip](https://docs.nocamclub.com/examples/hello-clip.mp4) Made through this API: 768×1152, 10 s, with sound, 2 credits, 72 seconds, from [this photo](https://docs.nocamclub.com/examples/mascot.jpg). The call below is the one that made it. ## Call it **cURL** ```bash # A new Idempotency-Key for each new thing you want made, the same one when you retry it. curl https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: muse-video-$(date +%s)" \ -d '{ "model": "muse-video", "input": { "prompt": "The purple character from img1 looks straight into the camera, smiles and says clearly: \"One key. Every model. Build with the NoCam API.\" Then he gives a small nod. He stays in the same place, and the camera doesn'\''t move.", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }' ``` **JavaScript** ```js const res = await fetch("https://api.nocamclub.com/v1/generations", { method: "POST", headers: { Authorization: `Bearer ${process.env.NOCAM_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID(), }, body: JSON.stringify({ "model": "muse-video", "input": { "prompt": "The purple character from img1 looks straight into the camera, smiles and says clearly: \"One key. Every model. Build with the NoCam API.\" Then he gives a small nod. He stays in the same place, and the camera doesn't move.", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }), }); const generation = await res.json(); ``` **Python** ```python import os, uuid, requests res = requests.post( "https://api.nocamclub.com/v1/generations", headers={"Authorization": f"Bearer {os.environ['NOCAM_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())}, json={ "model": "muse-video", "input": { "prompt": "The purple character from img1 looks straight into the camera, smiles and says clearly: \"One key. Every model. Build with the NoCam API.\" Then he gives a small nod. He stays in the same place, and the camera doesn't move.", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }, timeout=90, ) generation = res.json() ``` **MCP tool** ```json { "name": "generate", "arguments": { "model": "muse-video", "prompt": "The purple character from img1 looks straight into the camera, smiles and says clearly: \"One key. Every model. Build with the NoCam API.\" Then he gives a small nod. He stays in the same place, and the camera doesn't move.", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } } ``` Then poll `GET /v1/generations/{id}` until it finishes. See [Generations](https://docs.nocamclub.com/api/generations.md). ## Options | Field | Takes | Default | What it is | |---|---|---|---| | `prompt` (required) | Up to 10000 characters | | What to make. Refer to files by order: img1, img2, video1, audio1. | | `aspect_ratio` | `9:16`, `16:9`, `1:1` | `9:16` | Only without a photo. With one, the result takes the photo's shape: crop the photo instead. | | `images` | Up to 1 | | Photos: file ids from /v1/uploads, or https addresses. | Any other field is refused. How files work: [Uploads](https://docs.nocamclub.com/api/uploads.md) and [Files in prompts](https://docs.nocamclub.com/api/files-in-prompts.md). ## Prices In credits (1 credit = $0.01), as of 2026-11-07. For the current list: `GET /v1/models/muse-video`. **2 credits** ($0.02) for each generation. --- # GPT Image 2.5 Sunburst > Bold graphic results: stickers, icons, punchy compositions. Source: https://docs.nocamclub.com/models/gpt-image-2.5-sunburst - **Model id:** `gpt-image-2.5-sunburst` - **Makes:** photos - **From:** 4 credits ($0.04) - **Routes:** 1, so if it's down the model is down ## Writing prompts - Name the format outright: "a die-cut sticker", "thick white border", "plain dark background". ## A real result: A sticker ![A die-cut sticker of the purple character holding a pair of large lime green curly braces.](https://docs.nocamclub.com/examples/sticker.jpg) Made through this API: 1024×1024, 4 credits, 48 seconds, from [this photo](https://docs.nocamclub.com/examples/mascot.jpg). The call below is the one that made it. ## Call it **cURL** ```bash # A new Idempotency-Key for each new thing you want made, the same one when you retry it. curl https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Prefer: wait=60" \ -H "Idempotency-Key: gpt-image-2.5-sunburst-$(date +%s)" \ -d '{ "model": "gpt-image-2.5-sunburst", "input": { "prompt": "A die-cut sticker of the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers, holding a pair of large lime green curly braces like the code symbols { and }, one in each hand. Thick white border around the whole figure, plain dark background. Polished 3D render.", "resolution": "1K", "quality": "medium", "aspect_ratio": "1:1", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }' ``` **JavaScript** ```js const res = await fetch("https://api.nocamclub.com/v1/generations", { method: "POST", headers: { Authorization: `Bearer ${process.env.NOCAM_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID(), Prefer: "wait=60", }, body: JSON.stringify({ "model": "gpt-image-2.5-sunburst", "input": { "prompt": "A die-cut sticker of the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers, holding a pair of large lime green curly braces like the code symbols { and }, one in each hand. Thick white border around the whole figure, plain dark background. Polished 3D render.", "resolution": "1K", "quality": "medium", "aspect_ratio": "1:1", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }), }); const generation = await res.json(); ``` **Python** ```python import os, uuid, requests res = requests.post( "https://api.nocamclub.com/v1/generations", headers={"Authorization": f"Bearer {os.environ['NOCAM_API_KEY']}", "Prefer": "wait=60", "Idempotency-Key": str(uuid.uuid4())}, json={ "model": "gpt-image-2.5-sunburst", "input": { "prompt": "A die-cut sticker of the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers, holding a pair of large lime green curly braces like the code symbols { and }, one in each hand. Thick white border around the whole figure, plain dark background. Polished 3D render.", "resolution": "1K", "quality": "medium", "aspect_ratio": "1:1", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }, timeout=90, ) generation = res.json() ``` **MCP tool** ```json { "name": "generate", "arguments": { "model": "gpt-image-2.5-sunburst", "prompt": "A die-cut sticker of the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers, holding a pair of large lime green curly braces like the code symbols { and }, one in each hand. Thick white border around the whole figure, plain dark background. Polished 3D render.", "resolution": "1K", "quality": "medium", "aspect_ratio": "1:1", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } } ``` ## Options | Field | Takes | Default | What it is | |---|---|---|---| | `prompt` (required) | Up to 10000 characters | | What to make. Refer to files by order: img1, img2, video1, audio1. | | `aspect_ratio` | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3` | `1:1` | | | `resolution` | `1K`, `2K`, `4K` | `1K` | | | `quality` | `low`, `medium`, `high` | `medium` | | | `output_format` | `png`, `jpeg` | | | | `images` | Up to 8 | | Photos: file ids from /v1/uploads, or https addresses. | Any other field is refused. How files work: [Uploads](https://docs.nocamclub.com/api/uploads.md) and [Files in prompts](https://docs.nocamclub.com/api/files-in-prompts.md). ## Prices In credits (1 credit = $0.01), as of 2026-11-07. For the current list: `GET /v1/models/gpt-image-2.5-sunburst`. | Size | low | medium | high | |---|---|---|---| | 1K | 4 | 4 | 4 | | 2K | — | 9 | — | | 4K | — | 15 | — | --- # Grok Imagine > A photo from text alone, at the lowest price. Good for drafts and for many tries. Source: https://docs.nocamclub.com/models/grok-imagine - **Model id:** `grok-imagine` - **Makes:** photos - **From:** 2 credits ($0.02) - **Routes:** 1, so if it's down the model is down ## Writing prompts - It takes no photos: for that, use `grok-imagine-quality`. - Keep prompts direct, and judge the result for free ideas before moving to a dearer model. ## Good to know - Our content check matters most here, since this model's own rules are reported to be softer. The same [content rules](https://docs.nocamclub.com/rules.md) apply. ## Call it **cURL** ```bash # A new Idempotency-Key for each new thing you want made, the same one when you retry it. curl https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Prefer: wait=60" \ -H "Idempotency-Key: grok-imagine-$(date +%s)" \ -d '{ "model": "grok-imagine", "input": { "prompt": "A yellow taxi in the rain at night, neon reflections on the wet road", "resolution": "1K", "aspect_ratio": "16:9" } }' ``` **JavaScript** ```js const res = await fetch("https://api.nocamclub.com/v1/generations", { method: "POST", headers: { Authorization: `Bearer ${process.env.NOCAM_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID(), Prefer: "wait=60", }, body: JSON.stringify({ "model": "grok-imagine", "input": { "prompt": "A yellow taxi in the rain at night, neon reflections on the wet road", "resolution": "1K", "aspect_ratio": "16:9" } }), }); const generation = await res.json(); ``` **Python** ```python import os, uuid, requests res = requests.post( "https://api.nocamclub.com/v1/generations", headers={"Authorization": f"Bearer {os.environ['NOCAM_API_KEY']}", "Prefer": "wait=60", "Idempotency-Key": str(uuid.uuid4())}, json={ "model": "grok-imagine", "input": { "prompt": "A yellow taxi in the rain at night, neon reflections on the wet road", "resolution": "1K", "aspect_ratio": "16:9" } }, timeout=90, ) generation = res.json() ``` **MCP tool** ```json { "name": "generate", "arguments": { "model": "grok-imagine", "prompt": "A yellow taxi in the rain at night, neon reflections on the wet road", "resolution": "1K", "aspect_ratio": "16:9" } } ``` ## Options | Field | Takes | Default | What it is | |---|---|---|---| | `prompt` (required) | Up to 10000 characters | | What to make. Refer to files by order: img1, img2, video1, audio1. | | `aspect_ratio` | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3` | `1:1` | | | `resolution` | `1K`, `2K` | `1K` | | | `output_format` | `png`, `jpeg` | | | Any other field is refused. How files work: [Uploads](https://docs.nocamclub.com/api/uploads.md) and [Files in prompts](https://docs.nocamclub.com/api/files-in-prompts.md). ## Prices In credits (1 credit = $0.01), as of 2026-11-07. For the current list: `GET /v1/models/grok-imagine`. | Size | Credits | |---|---| | 1K | 2 | | 2K | 2 | --- # Grok Imagine Quality > The better Grok, and it takes your photos. Source: https://docs.nocamclub.com/models/grok-imagine-quality - **Model id:** `grok-imagine-quality` - **Makes:** photos - **From:** 3 credits ($0.03) - **Routes:** 1, so if it's down the model is down ## Writing prompts - Up to 8 photos: say what each one is for. ## Call it **cURL** ```bash # A new Idempotency-Key for each new thing you want made, the same one when you retry it. curl https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Prefer: wait=60" \ -H "Idempotency-Key: grok-imagine-quality-$(date +%s)" \ -d '{ "model": "grok-imagine-quality", "input": { "prompt": "img1 on a rooftop at night, city lights behind, phone photo", "resolution": "1K", "aspect_ratio": "3:4", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }' ``` **JavaScript** ```js const res = await fetch("https://api.nocamclub.com/v1/generations", { method: "POST", headers: { Authorization: `Bearer ${process.env.NOCAM_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID(), Prefer: "wait=60", }, body: JSON.stringify({ "model": "grok-imagine-quality", "input": { "prompt": "img1 on a rooftop at night, city lights behind, phone photo", "resolution": "1K", "aspect_ratio": "3:4", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }), }); const generation = await res.json(); ``` **Python** ```python import os, uuid, requests res = requests.post( "https://api.nocamclub.com/v1/generations", headers={"Authorization": f"Bearer {os.environ['NOCAM_API_KEY']}", "Prefer": "wait=60", "Idempotency-Key": str(uuid.uuid4())}, json={ "model": "grok-imagine-quality", "input": { "prompt": "img1 on a rooftop at night, city lights behind, phone photo", "resolution": "1K", "aspect_ratio": "3:4", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }, timeout=90, ) generation = res.json() ``` **MCP tool** ```json { "name": "generate", "arguments": { "model": "grok-imagine-quality", "prompt": "img1 on a rooftop at night, city lights behind, phone photo", "resolution": "1K", "aspect_ratio": "3:4", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } } ``` ## Options | Field | Takes | Default | What it is | |---|---|---|---| | `prompt` (required) | Up to 10000 characters | | What to make. Refer to files by order: img1, img2, video1, audio1. | | `aspect_ratio` | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3` | `1:1` | | | `resolution` | `1K`, `2K` | `1K` | | | `output_format` | `png`, `jpeg` | | | | `images` | Up to 8 | | Photos: file ids from /v1/uploads, or https addresses. | Any other field is refused. How files work: [Uploads](https://docs.nocamclub.com/api/uploads.md) and [Files in prompts](https://docs.nocamclub.com/api/files-in-prompts.md). ## Prices In credits (1 credit = $0.01), as of 2026-11-07. For the current list: `GET /v1/models/grok-imagine-quality`. | Size | Credits | |---|---| | 1K | 3 | | 2K | 3 | --- # Seedream 5.0 Flash > Cheap and quick, and it takes many reference photos at no extra cost. The price is the same at 1K and 2K. Source: https://docs.nocamclub.com/models/seedream-5.0-flash - **Model id:** `seedream-5.0-flash` - **Makes:** photos - **From:** 5 credits ($0.05) - **Routes:** 1, so if it's down the model is down ## Writing prompts - **It keeps whatever you don't mention from the photo, background and clothes included.** Name them when you want them changed. - It can crop tighter than you asked. If you need the whole figure, say "the whole figure, head to shoes, with space below the feet". ## Good to know - This model may refuse photos it takes for real people. A refusal gives the credits back. ## A real result: A picture for the agents page ![The purple character gives a high five to a small white robot on a city rooftop at night.](https://docs.nocamclub.com/examples/agents.jpg) Made through this API: 1280×720, 5 credits, 24 seconds, from [this photo](https://docs.nocamclub.com/examples/mascot.jpg). The call below is the one that made it. ## Call it **cURL** ```bash # A new Idempotency-Key for each new thing you want made, the same one when you retry it. curl https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Prefer: wait=60" \ -H "Idempotency-Key: seedream-5.0-flash-$(date +%s)" \ -d '{ "model": "seedream-5.0-flash", "input": { "prompt": "Keep the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers. He gives a high five to a small friendly white robot on a city rooftop at night, with blurred lights behind them. Purple and lime green tones, polished 3D render. No words or letters anywhere.", "resolution": "1K", "aspect_ratio": "16:9", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }' ``` **JavaScript** ```js const res = await fetch("https://api.nocamclub.com/v1/generations", { method: "POST", headers: { Authorization: `Bearer ${process.env.NOCAM_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID(), Prefer: "wait=60", }, body: JSON.stringify({ "model": "seedream-5.0-flash", "input": { "prompt": "Keep the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers. He gives a high five to a small friendly white robot on a city rooftop at night, with blurred lights behind them. Purple and lime green tones, polished 3D render. No words or letters anywhere.", "resolution": "1K", "aspect_ratio": "16:9", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }), }); const generation = await res.json(); ``` **Python** ```python import os, uuid, requests res = requests.post( "https://api.nocamclub.com/v1/generations", headers={"Authorization": f"Bearer {os.environ['NOCAM_API_KEY']}", "Prefer": "wait=60", "Idempotency-Key": str(uuid.uuid4())}, json={ "model": "seedream-5.0-flash", "input": { "prompt": "Keep the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers. He gives a high five to a small friendly white robot on a city rooftop at night, with blurred lights behind them. Purple and lime green tones, polished 3D render. No words or letters anywhere.", "resolution": "1K", "aspect_ratio": "16:9", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }, timeout=90, ) generation = res.json() ``` **MCP tool** ```json { "name": "generate", "arguments": { "model": "seedream-5.0-flash", "prompt": "Keep the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers. He gives a high five to a small friendly white robot on a city rooftop at night, with blurred lights behind them. Purple and lime green tones, polished 3D render. No words or letters anywhere.", "resolution": "1K", "aspect_ratio": "16:9", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } } ``` ## Options | Field | Takes | Default | What it is | |---|---|---|---| | `prompt` (required) | Up to 10000 characters | | What to make. Refer to files by order: img1, img2, video1, audio1. | | `aspect_ratio` | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3`, `21:9` | `1:1` | | | `resolution` | `1K`, `2K` | `1K` | | | `output_format` | `png`, `jpeg` | | | | `images` | Up to 10 | | Photos: file ids from /v1/uploads, or https addresses. | Any other field is refused. How files work: [Uploads](https://docs.nocamclub.com/api/uploads.md) and [Files in prompts](https://docs.nocamclub.com/api/files-in-prompts.md). ## Prices In credits (1 credit = $0.01), as of 2026-11-07. For the current list: `GET /v1/models/seedream-5.0-flash`. | Size | Credits | |---|---| | 1K | 5 | | 2K | 5 | --- # Seedream 5.0 Pro > Seedream with more detail, when Flash isn't enough. The price follows the size. Source: https://docs.nocamclub.com/models/seedream-5.0-pro - **Model id:** `seedream-5.0-pro` - **Makes:** photos - **From:** 11 credits ($0.11) - **Routes:** 1, so if it's down the model is down ## Writing prompts - **It keeps whatever you don't mention from the photo, background and clothes included.** Name them when you want them changed. ## Good to know - This model may refuse photos it takes for real people. A refusal gives the credits back. ## Call it **cURL** ```bash # A new Idempotency-Key for each new thing you want made, the same one when you retry it. curl https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Prefer: wait=60" \ -H "Idempotency-Key: seedream-5.0-pro-$(date +%s)" \ -d '{ "model": "seedream-5.0-pro", "input": { "prompt": "img1 in a small cafe, wearing a green coat, morning light, phone photo", "resolution": "2K", "aspect_ratio": "4:3", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }' ``` **JavaScript** ```js const res = await fetch("https://api.nocamclub.com/v1/generations", { method: "POST", headers: { Authorization: `Bearer ${process.env.NOCAM_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID(), Prefer: "wait=60", }, body: JSON.stringify({ "model": "seedream-5.0-pro", "input": { "prompt": "img1 in a small cafe, wearing a green coat, morning light, phone photo", "resolution": "2K", "aspect_ratio": "4:3", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }), }); const generation = await res.json(); ``` **Python** ```python import os, uuid, requests res = requests.post( "https://api.nocamclub.com/v1/generations", headers={"Authorization": f"Bearer {os.environ['NOCAM_API_KEY']}", "Prefer": "wait=60", "Idempotency-Key": str(uuid.uuid4())}, json={ "model": "seedream-5.0-pro", "input": { "prompt": "img1 in a small cafe, wearing a green coat, morning light, phone photo", "resolution": "2K", "aspect_ratio": "4:3", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }, timeout=90, ) generation = res.json() ``` **MCP tool** ```json { "name": "generate", "arguments": { "model": "seedream-5.0-pro", "prompt": "img1 in a small cafe, wearing a green coat, morning light, phone photo", "resolution": "2K", "aspect_ratio": "4:3", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } } ``` ## Options | Field | Takes | Default | What it is | |---|---|---|---| | `prompt` (required) | Up to 10000 characters | | What to make. Refer to files by order: img1, img2, video1, audio1. | | `aspect_ratio` | `1:1`, `16:9`, `9:16`, `4:3`, `3:4`, `3:2`, `2:3`, `21:9` | `1:1` | | | `resolution` | `1K`, `2K` | `1K` | | | `output_format` | `png`, `jpeg` | | | | `images` | Up to 10 | | Photos: file ids from /v1/uploads, or https addresses. | Any other field is refused. How files work: [Uploads](https://docs.nocamclub.com/api/uploads.md) and [Files in prompts](https://docs.nocamclub.com/api/files-in-prompts.md). ## Prices In credits (1 credit = $0.01), as of 2026-11-07. For the current list: `GET /v1/models/seedream-5.0-pro`. | Size | Credits | |---|---| | 1K | 11 | | 2K | 21 | --- # Omni Flash > A short clip with sound, from text or from up to 3 photos, at a very good price. With a video in, it changes that video. Source: https://docs.nocamclub.com/models/omni-flash - **Model id:** `omni-flash` - **Makes:** videos - **From:** 12 credits ($0.12) - **Routes:** 1, so if it's down the model is down ## Writing prompts - `reference_mode: "frames"` starts the clip on your first photo and ends it on your second. - With a video among the files, this is video editing: say what changes. The length follows your video, so don't send `duration`. - One action per clip. Simple movement holds up best. ## Good to know - It refuses words about children, celebrities and well-known characters, and can be strict about it. - Expect a couple of minutes. ## Call it **cURL** ```bash # A new Idempotency-Key for each new thing you want made, the same one when you retry it. curl https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: omni-flash-$(date +%s)" \ -d '{ "model": "omni-flash", "input": { "prompt": "A paper boat sails down a rain gutter, slow camera move, sound of rain", "duration": 8, "resolution": "720p", "aspect_ratio": "9:16" } }' ``` **JavaScript** ```js const res = await fetch("https://api.nocamclub.com/v1/generations", { method: "POST", headers: { Authorization: `Bearer ${process.env.NOCAM_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID(), }, body: JSON.stringify({ "model": "omni-flash", "input": { "prompt": "A paper boat sails down a rain gutter, slow camera move, sound of rain", "duration": 8, "resolution": "720p", "aspect_ratio": "9:16" } }), }); const generation = await res.json(); ``` **Python** ```python import os, uuid, requests res = requests.post( "https://api.nocamclub.com/v1/generations", headers={"Authorization": f"Bearer {os.environ['NOCAM_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())}, json={ "model": "omni-flash", "input": { "prompt": "A paper boat sails down a rain gutter, slow camera move, sound of rain", "duration": 8, "resolution": "720p", "aspect_ratio": "9:16" } }, timeout=90, ) generation = res.json() ``` **MCP tool** ```json { "name": "generate", "arguments": { "model": "omni-flash", "prompt": "A paper boat sails down a rain gutter, slow camera move, sound of rain", "duration": 8, "resolution": "720p", "aspect_ratio": "9:16" } } ``` Then poll `GET /v1/generations/{id}` until it finishes. See [Generations](https://docs.nocamclub.com/api/generations.md). ## Options | Field | Takes | Default | What it is | |---|---|---|---| | `prompt` (required) | Up to 10000 characters | | What to make. Refer to files by order: img1, img2, video1, audio1. | | `aspect_ratio` | `16:9`, `9:16` | `16:9` | | | `resolution` | `720p`, `1080p` | `720p` | | | `duration` | `8`, `4`, `6`, `10` | `8` | Clip length, seconds. | | `reference_mode` | `ingredients`, `frames` | `ingredients` | How the photos are used. | | `images` | Up to 3 | | Photos: file ids from /v1/uploads, or https addresses. | | `videos` | Up to 1 | | Videos, up to 10 s in total: file ids from /v1/uploads, or https addresses. | Any other field is refused. How files work: [Uploads](https://docs.nocamclub.com/api/uploads.md) and [Files in prompts](https://docs.nocamclub.com/api/files-in-prompts.md). ## Prices In credits (1 credit = $0.01), as of 2026-11-07. For the current list: `GET /v1/models/omni-flash`. | Length | 720p | 1080p | |---|---|---| | 4 s | 12 | 12 | | 6 s | 15 | 15 | | 8 s | 20 | 20 | | 10 s | 25 | 25 | With a video among the files (`with_video`), when its length sets the clip's: 720p: 20, 1080p: 20. --- # Seedance 2.0 Fast > Seedance for less, up to 15 seconds. The usual choice when you don't need 1080p or longer clips. Source: https://docs.nocamclub.com/models/seedance-2.0-fast - **Model id:** `seedance-2.0-fast` - **Makes:** videos - **From:** 18 credits ($0.18) - **Routes:** 2 ## Writing prompts - Name every file and say what it's for. See [Files in prompts](https://docs.nocamclub.com/api/files-in-prompts.md). - Audio needs a photo or a video next to it. - `reference_mode: "frames"` sets the first and last frame. ## Good to know - **Video among the files costs much more.** Those prices have `with_video: true`. All videos together: up to 15 s. Photos and audio files don't change the price. - Reference videos showing a person may be refused as a real person, even when they're AI-made. ## Call it **cURL** ```bash # A new Idempotency-Key for each new thing you want made, the same one when you retry it. curl https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: seedance-2.0-fast-$(date +%s)" \ -d '{ "model": "seedance-2.0-fast", "input": { "prompt": "img1 waves at the camera on a sunny street, slow camera move", "duration": 5, "resolution": "720p", "aspect_ratio": "9:16", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }' ``` **JavaScript** ```js const res = await fetch("https://api.nocamclub.com/v1/generations", { method: "POST", headers: { Authorization: `Bearer ${process.env.NOCAM_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID(), }, body: JSON.stringify({ "model": "seedance-2.0-fast", "input": { "prompt": "img1 waves at the camera on a sunny street, slow camera move", "duration": 5, "resolution": "720p", "aspect_ratio": "9:16", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }), }); const generation = await res.json(); ``` **Python** ```python import os, uuid, requests res = requests.post( "https://api.nocamclub.com/v1/generations", headers={"Authorization": f"Bearer {os.environ['NOCAM_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())}, json={ "model": "seedance-2.0-fast", "input": { "prompt": "img1 waves at the camera on a sunny street, slow camera move", "duration": 5, "resolution": "720p", "aspect_ratio": "9:16", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }, timeout=90, ) generation = res.json() ``` **MCP tool** ```json { "name": "generate", "arguments": { "model": "seedance-2.0-fast", "prompt": "img1 waves at the camera on a sunny street, slow camera move", "duration": 5, "resolution": "720p", "aspect_ratio": "9:16", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } } ``` Then poll `GET /v1/generations/{id}` until it finishes. See [Generations](https://docs.nocamclub.com/api/generations.md). ## Options | Field | Takes | Default | What it is | |---|---|---|---| | `prompt` (required) | Up to 10000 characters | | What to make. Refer to files by order: img1, img2, video1, audio1. | | `aspect_ratio` | `9:16`, `16:9`, `1:1`, `3:4`, `4:3`, `21:9` | `9:16` | | | `resolution` | `720p`, `480p` | `720p` | | | `duration` | `5`, `4`, `6`, `8`, `10`, `12`, `15` | `5` | Clip length, seconds. | | `reference_mode` | `ingredients`, `frames` | `ingredients` | How the photos are used. | | `images` | Up to 9 | | Photos: file ids from /v1/uploads, or https addresses. | | `videos` | Up to 3 | | Videos, up to 15 s in total: file ids from /v1/uploads, or https addresses. | | `audios` | Up to 3 | | Audio files, up to 15 s each: file ids from /v1/uploads, or https addresses. | Any other field is refused. How files work: [Uploads](https://docs.nocamclub.com/api/uploads.md) and [Files in prompts](https://docs.nocamclub.com/api/files-in-prompts.md). ## Prices In credits (1 credit = $0.01), as of 2026-11-07. For the current list: `GET /v1/models/seedance-2.0-fast`. | Length | 720p | 480p | |---|---|---| | 4 s | 35 | 18 | | 5 s | 35 | 23 | | 6 s | 45 | 27 | | 8 s | 60 | 36 | | 10 s | 80 | 45 | | 12 s | 95 | 54 | | 15 s | 120 | 67 | With a video among the files (`with_video`): | Length | 720p | 480p | |---|---|---| | 4 s | 190 | 190 | | 5 s | 190 | 200 | | 6 s | 190 | 210 | | 8 s | 190 | 230 | | 10 s | 190 | 250 | | 12 s | 190 | 270 | | 15 s | 190 | 300 | --- # Seedance 2.5 > Our strongest video model: up to 30 seconds and 1080p, with photos, videos and audio as references. Source: https://docs.nocamclub.com/models/seedance-2.5 - **Model id:** `seedance-2.5` - **Makes:** videos - **From:** 30 credits ($0.30) - **Routes:** 2 ## Writing prompts - Name every file and say what it's for: "img1 walks through the city from img2, moving like the dancer in video1, to the rhythm of audio1." See [Files in prompts](https://docs.nocamclub.com/api/files-in-prompts.md). - With `reference_mode: "frames"` you set the first and last frame. With `ingredients`, the default, the model uses the files freely. - Sound is generated with the picture, and you can steer it in the prompt. ## Good to know - **Video among the files costs much more.** Those prices have `with_video: true`, because the seconds of your video are billed too. All videos together: up to 30 s. Photos and audio files don't change the price. - Reference videos showing a person may be refused as a real person, even when they're AI-made. Video without people, or a photo, is safer. - Long clips take minutes: 5 to 10 is normal. Poll. ## Call it **cURL** ```bash # A new Idempotency-Key for each new thing you want made, the same one when you retry it. curl https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: seedance-2.5-$(date +%s)" \ -d '{ "model": "seedance-2.5", "input": { "prompt": "img1 walks along a rainy street at night, neon signs, slow camera move", "duration": 5, "resolution": "720p", "aspect_ratio": "9:16", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }' ``` **JavaScript** ```js const res = await fetch("https://api.nocamclub.com/v1/generations", { method: "POST", headers: { Authorization: `Bearer ${process.env.NOCAM_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID(), }, body: JSON.stringify({ "model": "seedance-2.5", "input": { "prompt": "img1 walks along a rainy street at night, neon signs, slow camera move", "duration": 5, "resolution": "720p", "aspect_ratio": "9:16", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }), }); const generation = await res.json(); ``` **Python** ```python import os, uuid, requests res = requests.post( "https://api.nocamclub.com/v1/generations", headers={"Authorization": f"Bearer {os.environ['NOCAM_API_KEY']}", "Idempotency-Key": str(uuid.uuid4())}, json={ "model": "seedance-2.5", "input": { "prompt": "img1 walks along a rainy street at night, neon signs, slow camera move", "duration": 5, "resolution": "720p", "aspect_ratio": "9:16", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } }, timeout=90, ) generation = res.json() ``` **MCP tool** ```json { "name": "generate", "arguments": { "model": "seedance-2.5", "prompt": "img1 walks along a rainy street at night, neon signs, slow camera move", "duration": 5, "resolution": "720p", "aspect_ratio": "9:16", "images": [ "https://docs.nocamclub.com/examples/mascot.jpg" ] } } ``` Then poll `GET /v1/generations/{id}` until it finishes. See [Generations](https://docs.nocamclub.com/api/generations.md). ## Options | Field | Takes | Default | What it is | |---|---|---|---| | `prompt` (required) | Up to 10000 characters | | What to make. Refer to files by order: img1, img2, video1, audio1. | | `aspect_ratio` | `9:16`, `16:9`, `1:1`, `3:4`, `4:3`, `21:9` | `9:16` | | | `resolution` | `720p`, `1080p`, `480p` | `720p` | | | `duration` | `5`, `4`, `6`, `8`, `10`, `12`, `15`, `20`, `25`, `30` | `5` | Clip length, seconds. | | `reference_mode` | `ingredients`, `frames` | `ingredients` | How the photos are used. | | `images` | Up to 30 | | Photos: file ids from /v1/uploads, or https addresses. | | `videos` | Up to 10 | | Videos, up to 30 s in total: file ids from /v1/uploads, or https addresses. | | `audios` | Up to 10 | | Audio files, up to 15 s each: file ids from /v1/uploads, or https addresses. | Any other field is refused. How files work: [Uploads](https://docs.nocamclub.com/api/uploads.md) and [Files in prompts](https://docs.nocamclub.com/api/files-in-prompts.md). ## Prices In credits (1 credit = $0.01), as of 2026-11-07. For the current list: `GET /v1/models/seedance-2.5`. | Length | 720p | 1080p | 480p | |---|---|---|---| | 4 s | 60 | 74 | 30 | | 5 s | 60 | 200 | 37 | | 6 s | 90 | 200 | 44 | | 8 s | 90 | 260 | 59 | | 10 s | 90 | 300 | 73 | | 12 s | 130 | 350 | 88 | | 15 s | 130 | 430 | 110 | | 20 s | 200 | 430 | 146 | | 25 s | 200 | 460 | 183 | | 30 s | 200 | 640 | 219 | With a video among the files (`with_video`): | Length | 720p | 1080p | 480p | |---|---|---|---| | 4 s | 600 | 408 | 340 | | 5 s | 650 | 420 | 350 | | 6 s | 700 | 432 | 360 | | 8 s | 810 | 456 | 380 | | 10 s | 910 | 480 | 400 | | 12 s | 1010 | 504 | 420 | | 15 s | 1170 | 540 | 450 | | 20 s | 1430 | 600 | 500 | | 25 s | 1680 | 660 | 550 | | 30 s | 1940 | 720 | 600 | --- # GPT-6 Luna > A quick, cheap text model that can look at photos. Good for drafting prompts, captions and short answers. Source: https://docs.nocamclub.com/models/gpt-6-luna - **Model id:** `gpt-6-luna` - **Makes:** text - **From:** 1 credits ($0.01) - **Routes:** 1, so if it's down the model is down ## Writing prompts - A text generation's result is in `outputs[0].text`, as the model wrote it, markdown included. ## Call it **cURL** ```bash # A new Idempotency-Key for each new thing you want made, the same one when you retry it. curl https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Prefer: wait=60" \ -H "Idempotency-Key: gpt-6-luna-$(date +%s)" \ -d '{ "model": "gpt-6-luna", "input": { "prompt": "Write three short captions for a photo of a yellow taxi in the rain." } }' ``` **JavaScript** ```js const res = await fetch("https://api.nocamclub.com/v1/generations", { method: "POST", headers: { Authorization: `Bearer ${process.env.NOCAM_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID(), Prefer: "wait=60", }, body: JSON.stringify({ "model": "gpt-6-luna", "input": { "prompt": "Write three short captions for a photo of a yellow taxi in the rain." } }), }); const generation = await res.json(); ``` **Python** ```python import os, uuid, requests res = requests.post( "https://api.nocamclub.com/v1/generations", headers={"Authorization": f"Bearer {os.environ['NOCAM_API_KEY']}", "Prefer": "wait=60", "Idempotency-Key": str(uuid.uuid4())}, json={ "model": "gpt-6-luna", "input": { "prompt": "Write three short captions for a photo of a yellow taxi in the rain." } }, timeout=90, ) generation = res.json() ``` **MCP tool** ```json { "name": "generate", "arguments": { "model": "gpt-6-luna", "prompt": "Write three short captions for a photo of a yellow taxi in the rain." } } ``` ## Options | Field | Takes | Default | What it is | |---|---|---|---| | `prompt` (required) | Up to 10000 characters | | What to make. Refer to files by order: img1, img2, video1, audio1. | | `images` | Up to 4 | | Photos: file ids from /v1/uploads, or https addresses. | Any other field is refused. How files work: [Uploads](https://docs.nocamclub.com/api/uploads.md) and [Files in prompts](https://docs.nocamclub.com/api/files-in-prompts.md). ## Prices In credits (1 credit = $0.01), as of 2026-11-07. For the current list: `GET /v1/models/gpt-6-luna`. **1 credits** ($0.01) for each generation. --- # Claude Opus 5.5 > A strong text model for harder writing and reasoning. Source: https://docs.nocamclub.com/models/claude-opus-5.5 - **Model id:** `claude-opus-5.5` - **Makes:** text - **From:** 10 credits ($0.10) - **Routes:** 2 ## Writing prompts - A text generation's result is in `outputs[0].text`, as the model wrote it, markdown included. ## Call it **cURL** ```bash # A new Idempotency-Key for each new thing you want made, the same one when you retry it. curl https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Prefer: wait=60" \ -H "Idempotency-Key: claude-opus-5.5-$(date +%s)" \ -d '{ "model": "claude-opus-5.5", "input": { "prompt": "Write a shooting plan for a 15-second clip of a paper boat in a rain gutter, shot by shot." } }' ``` **JavaScript** ```js const res = await fetch("https://api.nocamclub.com/v1/generations", { method: "POST", headers: { Authorization: `Bearer ${process.env.NOCAM_API_KEY}`, "Content-Type": "application/json", "Idempotency-Key": crypto.randomUUID(), Prefer: "wait=60", }, body: JSON.stringify({ "model": "claude-opus-5.5", "input": { "prompt": "Write a shooting plan for a 15-second clip of a paper boat in a rain gutter, shot by shot." } }), }); const generation = await res.json(); ``` **Python** ```python import os, uuid, requests res = requests.post( "https://api.nocamclub.com/v1/generations", headers={"Authorization": f"Bearer {os.environ['NOCAM_API_KEY']}", "Prefer": "wait=60", "Idempotency-Key": str(uuid.uuid4())}, json={ "model": "claude-opus-5.5", "input": { "prompt": "Write a shooting plan for a 15-second clip of a paper boat in a rain gutter, shot by shot." } }, timeout=90, ) generation = res.json() ``` **MCP tool** ```json { "name": "generate", "arguments": { "model": "claude-opus-5.5", "prompt": "Write a shooting plan for a 15-second clip of a paper boat in a rain gutter, shot by shot." } } ``` ## Options | Field | Takes | Default | What it is | |---|---|---|---| | `prompt` (required) | Up to 10000 characters | | What to make. Refer to files by order: img1, img2, video1, audio1. | | `images` | Up to 4 | | Photos: file ids from /v1/uploads, or https addresses. | Any other field is refused. How files work: [Uploads](https://docs.nocamclub.com/api/uploads.md) and [Files in prompts](https://docs.nocamclub.com/api/files-in-prompts.md). ## Prices In credits (1 credit = $0.01), as of 2026-11-07. For the current list: `GET /v1/models/claude-opus-5.5`. **10 credits** ($0.10) for each generation. --- # From a photo to a talking clip > Two calls. Make the picture you want, then make it speak. Source: https://docs.nocamclub.com/guides/photo-to-clip A common job: take one photo, put the person in a new place, and have them say something. Doing it in two steps gives you a look at the frame before you pay for the clip. The commands use [jq](https://jqlang.org) to pick fields out of the answers. `RUN` makes this run's idempotency keys its own, so you can run the guide more than once: ```bash RUN=$(date +%s) ``` ## 1. Upload the photo ```bash PHOTO_ID=$(curl -s https://api.nocamclub.com/v1/uploads \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "url": "https://docs.nocamclub.com/examples/mascot.jpg" }' | jq -r .id) ``` Use your own photo's address instead. The `id` works for 48 hours. ## 2. Make the frame Vertical, since that's what the clip will be. Say what to keep. ```bash FRAME_URL=$(curl -s https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Prefer: wait=60" \ -H "Idempotency-Key: rooftop-frame-$RUN" \ -d '{ "model": "nano-banana-2", "input": { "prompt": "Keep the face and hair of img1. The same person on a city rooftop at sunset, facing the camera, waist up. Phone photo.", "images": ["'"$PHOTO_ID"'"], "resolution": "2K", "aspect_ratio": "9:16" } }' | jq -r '.outputs[0].url') ``` Look at the result. If it isn't right, change the prompt and make another: a photo costs little and a clip costs more. ## 3. Make it speak A result is a public link, so it goes straight to the next model. Muse always makes 10 seconds with sound, and its shape follows the photo. About 2 words a second fits the length. ```bash CLIP_ID=$(curl -s https://api.nocamclub.com/v1/generations \ -H "Authorization: Bearer $NOCAM_API_KEY" \ -H "Content-Type: application/json" \ -H "Idempotency-Key: rooftop-clip-$RUN" \ -d '{ "model": "muse-video", "input": { "prompt": "img1 looks straight into the camera, smiles and says clearly: \"I made this whole video from one selfie.\" The camera does not move.", "images": ["'"$FRAME_URL"'"] } }' | jq -r .id) ``` Then poll `GET /v1/generations/$CLIP_ID` until `status` is `succeeded` or `failed`, usually a minute or two. ## Why two steps - **You check the expensive part's input.** A bad frame costs a few credits. A bad clip costs more, and takes longer to find out. - **You choose per step.** Use the model that's best at photos, then the one that's best at clips. - **Failures stay small.** If the clip fails, the credits come back and the frame is still there. ## Keep it working in production - Send a new `Idempotency-Key` per clip, and reuse it for retries of that clip. - Read `error.code`: on `content_refused`, tell the person. On `provider_unavailable`, try again in a few minutes. - Download the result: links stop after 7 days. --- # The same character across many photos > How to keep a person or a mascot looking like themselves from shot to shot. Source: https://docs.nocamclub.com/guides/same-character Every photo on this site's pages shows the same character, made through this API. This is how. ![The same character on a brick wall, made from one photo and a logo.](https://docs.nocamclub.com/examples/share-card.jpg) ## Start from one clean photo One subject, front on, plain background, nothing hiding the face. That's what we used: ![A purple character in a black cap, yellow sunglasses, black hoodie and sneakers, standing front on against a plain background.](https://docs.nocamclub.com/examples/mascot.jpg) ## Describe what must not change Models keep what you name. Write the same description into every prompt, word for word: ```text Keep the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers. ``` Then say what's new, in a second sentence. ```json { "model": "nano-banana-pro", "input": { "prompt": "Keep the purple character from img1, with the same black cap, yellow sunglasses, black hoodie, cargo pants and sneakers. He plugs a glowing lime green cable into the back of a small friendly white robot.", "images": ["https://docs.nocamclub.com/examples/mascot.jpg"], "resolution": "2K", "aspect_ratio": "16:9" } } ``` ## Reuse the file Upload the photo once and use its `file_…` id everywhere, so each generation starts from the same bytes. Files stay for 48 hours, so upload again for later work. ## Add a second file for the details Need a logo on the wall? Send it as `img2` and say where it goes. That's how the picture at the top of this page was made. ## What drifts Small details go first, particularly on video. In our clip, the character's yellow sunglasses came out dark purple. So: - Check the details that matter on each result. - Put them in the prompt by name if they keep drifting. - For a series, make every frame from the original photo, not from the previous result. Copies of copies drift further. ## Which model - `nano-banana-pro` for holding a look across angles. - `nano-banana-2` when you need it cheaper or at 4K. - `seedream-5.0-flash` when you have many reference photos of the same subject. Real people: use only photos of yourself or of someone who agreed, and expect some models to refuse. See [Content rules](https://docs.nocamclub.com/rules.md). --- # Changelog > What changed in the API. Source: https://docs.nocamclub.com/changelog ## November 2026 - **Seedance takes more.** Seedance 2.5 takes up to 30 photos, 10 videos (30 s together) and 10 audio files. Seedance 2.0 Fast takes 9, 3 (15 s together) and 3, adds 480p and takes a first and a last frame. - **File lengths are checked before the charge.** Uploads now report `duration_seconds`, and a video or audio file over a model's limit is refused with `invalid_parameter`. - **Clearer failures.** A failed generation now says why: `provider_unavailable`, `input_refused`, `bad_input_file`, `unsupported_request`, `prompt_too_long` or `output_limit`. - **MCP tries again when it should.** Asking `generate` again after a failure or a deletion starts a new generation. After a success it still returns the same one for 10 minutes, so an agent's retry can't pay twice. - **OpenAPI.** `GET /v1/openapi.json` describes the whole API. - **Errors point at their page.** A failed generation's `error` now has `docs_url`, like a refused call's. - **One spelling.** An estimate's `params` are spelled as in a request: `aspect_ratio`, not `aspectRatio`. - **The sandbox's samples look real.** They carry `width`, `height`, `duration_seconds` and `has_audio`, so you can test the checks you'll run on real results. - **These docs**, with a Markdown copy of every page, `llms.txt` and a skill file for agents.