Skip to content

Developer API

Create photos and videos with every model on Yumeforge from your own app, script or server. One key, plain JSON, and the same credits you use in the studio.

Overview

The API is a small REST API at https://yumeforge.com/api/v1. Requests and replies are JSON (uploads use multipart). Generation is asynchronous: you start a job, then poll it until it is completed or failed. Results are links to files we store for you.

  1. Pick a model with GET /models and read its options.
  2. Start a job with POST /generate.
  3. Poll GET /jobs/{id} every few seconds and download the outputs.

Jobs you start through the API also appear in your library in the studio. The API can be called from any origin (CORS is open), but it never uses your login cookie: every request needs a key.

Authentication

Create a key on your API keys page. Keys start with yf_live_ and are shown only once, so store the key right away. Send it in the Authorization header of every request:

Header
Authorization: Bearer yf_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
  • Anyone with a key can spend your credits. Keep keys on your server and out of public repositories and web pages.
  • You can have up to 10 active keys. Revoke a key and it stops working immediately.
  • Requests with a missing, malformed or revoked key get 401.

Quick start

Save your key in an environment variable, then start a job. This example uses FLUX Schnell, a fast text-to-image model (from 2 credits per image).

Set your key
export YF_API_KEY="yf_live_..."
Start a job
curl -X POST https://yumeforge.com/api/v1/generate \
  -H "Authorization: Bearer $YF_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "studio/flux-schnell",
    "input": { "prompt": "A lighthouse at dusk, film photo", "size": "1024*1024" }
  }'

The reply contains the job id and the credits reserved for it:

Reply
{ "id": "5f1c2e1a-8d4b-4a53-9a55-0c8f3d2b7e10", "status": "processing", "credits": 2 }

Poll the job every 2 to 5 seconds until the status is completed or failed:

Check the job
curl https://yumeforge.com/api/v1/jobs/JOB_ID \
  -H "Authorization: Bearer $YF_API_KEY"
Completed job
{
  "job": {
    "id": "5f1c2e1a-8d4b-4a53-9a55-0c8f3d2b7e10",
    "status": "completed",
    "model": "studio/flux-schnell",
    "modelLabel": "FLUX Schnell",
    "output": "image",
    "outputs": ["https://yumeforge.com/api/media/…/result.jpg"],
    "text": null,
    "error": null,
    "credits": 2,
    "createdAt": "2026-09-30T10:00:00.000Z",
    "completedAt": "2026-09-30T10:00:04.000Z"
  }
}

JavaScript and Python

The same flow, generate and then poll, in two languages.

JavaScript
// Node 18+ or any modern runtime with fetch. Keep the key on your server.
const API = "https://yumeforge.com/api/v1";
const headers = {
  Authorization: `Bearer ${process.env.YF_API_KEY}`,
  "Content-Type": "application/json",
};

async function call(path, init = {}) {
  const res = await fetch(API + path, { ...init, headers });
  const data = await res.json();
  if (!res.ok) throw new Error(`${data.error.code}: ${data.error.message}`);
  return data;
}

const job = await call("/generate", {
  method: "POST",
  body: JSON.stringify({
    model: "studio/flux-schnell",
    input: { prompt: "A lighthouse at dusk, film photo" },
  }),
});

let result;
do {
  await new Promise((r) => setTimeout(r, 3000));
  ({ job: result } = await call(`/jobs/${job.id}`));
} while (result.status === "queued" || result.status === "processing");

if (result.status === "completed") console.log(result.outputs);
else console.error(result.error);
Python
# pip install requests
import os, time, requests

API = "https://yumeforge.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['YF_API_KEY']}"}

def call(method, path, **kwargs):
    res = requests.request(method, API + path, headers=HEADERS, timeout=60, **kwargs)
    data = res.json()
    if not res.ok:
        raise RuntimeError(f"{data['error']['code']}: {data['error']['message']}")
    return data

job = call("POST", "/generate", json={
    "model": "studio/flux-schnell",
    "input": {"prompt": "A lighthouse at dusk, film photo"},
})

while True:
    time.sleep(3)
    result = call("GET", f"/jobs/{job['id']}")["job"]
    if result["status"] not in ("queued", "processing"):
        break

print(result["outputs"] if result["status"] == "completed" else result["error"])

Endpoints

All paths are relative to https://yumeforge.com. Every request needs the Authorization header.

GET/api/v1/models

All models you can use. Filter with ?category=<id>.

Returns
{ models: Model[], count }

GET/api/v1/models/{id}

One model with its options. The id contains slashes, use it as is.

Returns
{ model: Model }

POST/api/v1/generate

Start a generation. Credits are reserved right away and returned if it fails.

Body
{ model, input }
Returns
{ id, status, credits }

GET/api/v1/jobs/{id}

Status and results of one of your jobs. Poll every 2 to 5 seconds.

Returns
{ job: Job }

GET/api/v1/balance

Your credit balance.

Returns
{ credits }

POST/api/v1/uploads

Upload a picture, video or audio file to use as input (multipart, field "file").

Body
multipart/form-data
Returns
{ id, url, kind, name }

The Model object

params lists every option the model accepts, with its type, allowed values (enum), default, range and whether it is required. Options with media take a file URL. Categories: image, edit, video, video-edit, avatar, motion, upscale, 3d, analyze, train.

Model
{
  "id": "studio/flux-schnell",
  "label": "FLUX Schnell",
  "brand": "FLUX",
  "category": "image",
  "output": "image",
  "consentRequired": false,
  "fromCredits": 2,
  "price": "from 2 credits",
  "params": [
    { "name": "prompt", "type": "string", "required": true, "description": "The positive prompt for the generation." },
    { "name": "num_images", "type": "integer", "default": 1, "minimum": 1, "maximum": 4, "required": false, "description": "…" }
  ]
}

The Job object

status is queued, processing, completed or failed. outputs holds absolute links to the result files; models that answer in text put it in text. When a job fails, error says why and the credits go back to your balance.

Inputs and files

Put the model options in input, using the names from params. Unknown options are ignored, numbers are kept inside their range and enum values are checked.

Files. For options that take a picture, video or audio file, pass a public https URL. If the file is on your computer, upload it first with POST /api/v1/uploads (up to 50 MB) and pass the url from the reply. For bigger files, host them yourself and pass that link.

Upload a file
curl -X POST https://yumeforge.com/api/v1/uploads \
  -H "Authorization: Bearer $YF_API_KEY" \
  -F "file=@portrait.jpg"

Consent. Models that work on a real person (face swap, avatars, lip sync, training on a face and similar) have consentRequired: true. For those, add "_consent": true to input. By sending it you confirm that you have permission from everyone shown and that none of them is a public figure. Without it the request fails with 400. The confirmation is stored with the job.

Errors

Errors use normal HTTP status codes and always have the same shape. Show message to people; use code in your code.

Error
{
  "error": {
    "message": "This generation costs 40 credits. Top up to continue.",
    "code": "insufficient_credits"
  }
}
StatusCodeMeaning
400invalid_requestThe body or an option is wrong, or consent is missing. The message says what to fix.
401unauthorizedNo key, a malformed key, or a revoked key.
402insufficient_creditsNot enough credits for this generation. Top up and try again.
403forbiddenThe account is suspended, the terms are not accepted yet, or content was refused.
404not_foundUnknown model or job, or a job that is not yours.
413file_too_largeUploads through the API can be up to 50 MB.
415unsupported_file_typeUse an image, video, audio file or ZIP.
422content_blockedThe prompt or an uploaded picture breaks the content rules.
429rate_limitedToo many requests or running generations. Wait for the Retry-After header (seconds).
502generation_failedThe model could not start. Your credits were returned.
503unavailableMaintenance or full capacity. Try again in a few minutes.

Rate limits

  • 60 requests per minute per key, for all endpoints together.
  • 10 new generations per minute per key.
  • A limited number of generations can run at the same time per account (currently 4). Start the next one when a job finishes.

Over a limit you get 429 with a Retry-After header in seconds. Wait that long before trying again, and poll jobs no more often than every 2 seconds.

Credits and pricing

The API uses the credits on your account, at the same prices as the studio (1 credit is €0.01 of generation). The price depends on the model and the options, like resolution, length and number of results. fromCredits on each model is the price with default options; the reply of POST /generate shows what was actually reserved.

Credits are taken when a job starts and returned automatically when it fails. Check your balance with GET /api/v1/balance and top up on the pricing page.

Content policy

Everything made through the API follows the same rules as the studio. Prompts, uploaded pictures and results are checked automatically, and repeated violations can suspend the account and its keys. Read the acceptable use policy before you build, and make sure the people using your app follow it too.

Ready to build?

Create a key and make your first request in a minute.