Frenkel.ai Get an API key
REST API

Frenkel.ai Studio API

The API is the same set of routes the studio itself uses, so anything you can do in the browser you can do from code. Base URL https://app.frenkel.ai. The machine-readable description lives at /api/openapi.json (OpenAPI 3.1).

Authentication

Create a key under Account → Developers & AI agents. Keys start with frk_, are shown once, and can be revoked at any time. Send it as a bearer token:

Authorization: Bearer frk_your_key

A key acts as the account that created it and can spend its credits. Keep it server-side; revoke it immediately if it leaks.

Generation lifecycle

  1. Look at the menu. GET /api/catalog?locale=en returns every option with live availability and credit prices: tasks, image looks, video styles and tiers, aspect ratios, product scenes, voices, cue tags, dubbing languages, logo options and limits.
  2. Quote. GET /api/pricing?task=text_to_video&style=seedance25&tier=720p&seconds=5 runs the real router in preview mode and returns the exact credits.
  3. Start. POST /api/generations with a JSON body (see the schema below). Credits are charged now; the response is the job with status queued.
  4. Poll. GET /api/jobs/{id} until status is completed, failed or cancelled. Images take seconds, cloud video one to six minutes. Failed jobs are refunded.
  5. Download. Each output is an asset with url and thumbUrl under /api/files/…; send the same Authorization header. Reuse an output's id as inputAssetIds for the next step.

Endpoints

Method & pathPurpose
GET /api/meThe account behind the key and its credit balance.
GET /api/me/ledgerCredit movements (grants, purchases, charges, refunds).
GET /api/catalog?locale=enEverything the studio offers, with availability and prices.
GET /api/pricingQuote one choice in credits (task, quality, style, tier, seconds, count…).
POST /api/generationsStart a generation: any task, from images to dubbing and logos.
GET /api/jobs · GET /api/jobs/{id} · DELETE /api/jobs/{id}Recent jobs, one job with outputs, cancel.
GET /api/jobs/{id}/detailsTimeline, translated prompt, engine, model, provider cost.
GET /api/assets · GET|PATCH|DELETE /api/assets/{id}The library: search, kinds, media types, projects, pagination.
POST /api/assets/importAdd a file from a public URL or base64 (images ≤ 25 MB, video ≤ 600 MB, audio).
POST /api/uploadsMultipart upload (file, optional kind, projectId).
GET /api/files/{key}Download a stored file (Range supported).
GET|POST /api/projectsFolders for campaigns and clients.
GET|POST /api/charactersPeople kept consistent across images.
GET|POST /api/voicesCloned voices; register one, then run a voice_clone generation.
GET|POST /api/me/api-keys · DELETE /api/me/api-keys/{id}Manage keys.

Tasks

text_to_imageimage_editinpaintoutpaintbackground_replacebackground_removeupscalevariationproduct_photocharacter_referencetext_to_videoimage_to_videoreference_to_videotext_to_speechvideo_voiceovervoice_clonevideo_lipsyncvideo_dublogovectorizerecolormockup

The full request schema (GenerationRequest) with every field is in the OpenAPI document below. The most used fields: task, prompt, quality, aspectRatio, count, inputAssetIds, videoStyle, videoSeconds, cloudTier, voice, dub, logoOptions, mockupScene, projectId.

Examples

Create an image and wait for it (curl)

KEY=frk_your_key
JOB=$(curl -s https://app.frenkel.ai/api/generations \
  -H "Authorization: Bearer $KEY" -H "Content-Type: application/json" \
  -d '{"task":"text_to_image","prompt":"A ceramic cup on a wooden table, soft morning light","quality":"seedream","aspectRatio":"16:9"}' \
  | jq -r .id)

until curl -s https://app.frenkel.ai/api/jobs/$JOB -H "Authorization: Bearer $KEY" | jq -e '.status|IN("completed","failed","cancelled")' >/dev/null; do sleep 3; done
curl -s https://app.frenkel.ai/api/jobs/$JOB -H "Authorization: Bearer $KEY" | jq '.outputs[0].url'

Animate that image (JavaScript)

const headers = { Authorization: `Bearer ${process.env.FRENKEL_KEY}`, "Content-Type": "application/json" };
const base = "https://app.frenkel.ai";

const job = await fetch(`${base}/api/generations`, { method: "POST", headers, body: JSON.stringify({
  task: "image_to_video", inputAssetIds: [imageAssetId], videoStyle: "seedancemini", cloudTier: "720p", videoSeconds: 5,
  prompt: "slow push-in, steam rising from the cup",
}) }).then(r => r.json());

let done = job;
while (!["completed", "failed", "cancelled"].includes(done.status)) {
  await new Promise(r => setTimeout(r, 4000));
  done = await fetch(`${base}/api/jobs/${job.id}`, { headers }).then(r => r.json());
}
console.log(done.status, done.outputs[0]?.url);

A voice clip with cues (Python)

import requests, time
H = {"Authorization": "Bearer frk_your_key"}
job = requests.post("https://app.frenkel.ai/api/generations", headers=H, json={
    "task": "text_to_speech",
    "prompt": "Welcome to Frenkel Studio. [excited] Today we are making something special. [wait:1] Let's begin.",
    "voice": {"voice": "Sarah", "stability": 0.4},
}).json()
while job["status"] not in ("completed", "failed", "cancelled"):
    time.sleep(2); job = requests.get(f"https://app.frenkel.ai/api/jobs/{job['id']}", headers=H).json()
print(job["outputs"][0]["url"])

Errors

Errors are JSON: {"error": "message", "code": "…"}. 401 missing or revoked key · 400 invalid request (the message names the field) · 402 not enough credits · 404 unknown job or asset · 429 too many concurrent jobs (the account runs up to 5 at once).

OpenAPI reference

Interactive reference generated from the live openapi.json. Paste your key under Authentication to try requests against your own account.