Tokenless
← Text API documentation

Images, video, and Studio

Create and edit media with one Tokenless API key. Studio uses this same API and your existing balance. Media prices are quoted separately from text-token pricing; the text API’s 50% discount does not apply to media.

The job lifecycle

Upload references, request a quote, then submit a job. Jobs continue after you disconnect. Polling is free. Quotes expire after five minutes and become invalid when inputs change. Two media jobs can run per account at a time. Files are retained for 30 days; result download links last 15 minutes and can be refreshed by retrieving the job.

GET /media/modelsModel capabilities, availability, and enabled pricing configurations. Public.
POST /media/uploadsJSON {contentType, bytes}; returns an asset ID and a signed form upload valid for 15 minutes.
POST /media/quotesValidate normalized inputs and uploaded file contents; returns quote ID, chargeMicros, quantity, unit, expiresAt.
POST /media/jobsJSON {quoteId, input} plus Idempotency-Key. Returns the reserved job with HTTP 202.
GET /media/jobsYour 20 newest jobs. Use ?before=nextCursor for older records.
GET /media/jobs/:idOwned job, status, original inputs, reserved/charged amount, and outputs.
GET /media/assets/:idRefresh a validated reference asset’s temporary read URL.

Base URL: https://api.tokenless.store/api/v1. The /v1 prefix is also supported. Authenticate with Authorization: Bearer sk-tk-…. These normalized media endpoints are separate from OpenAI-compatible text endpoints.

Inputs and settings

operation is image, image_edit, video, video_edit, replace_people, or motion. Supply a model ID, prompt, image asset IDs, optional source video and lastFrame asset IDs, and settings. Model capabilities determine valid durations, resolutions, quality modes, audio, aspect ratios, and reference limits. Editing uses the uploaded video duration; omit settings.duration for edits and motion transfer.

References must be uploaded asset IDs owned by your account, not arbitrary URLs. Use still JPG, PNG, or WebP files up to 10 MB and at least 300 pixels on each side. Video uploads accept MP4/MOV up to 200 MB, with duration limits specific to the selected model. Original audio preservation is model-dependent.

javascript
// Node.js 22+. Keep TOKENLESS_API_KEY on your server.
import { readFile } from "node:fs/promises";
import { randomUUID } from "node:crypto";
const base = "https://api.tokenless.store/api/v1";
const headers = {
  Authorization: "Bearer " + process.env.TOKENLESS_API_KEY,
  "Content-Type": "application/json"
};
async function api(path, body, extra = {}) {
  const response = await fetch(base + path, {
    method: body ? "POST" : "GET", headers: {...headers, ...extra},
    ...(body ? {body: JSON.stringify(body)} : {})
  });
  const data = await response.json();
  if (!response.ok) throw new Error(data.error?.message || response.statusText);
  return data;
}
async function upload(path, contentType) {
  const bytes = await readFile(path);
  const asset = await api("/media/uploads", {contentType, bytes: bytes.length});
  const form = new FormData();
  for (const [key, value] of Object.entries(asset.upload.fields)) form.append(key, value);
  form.append("file", new Blob([bytes], {type: contentType}), "upload");
  const response = await fetch(asset.upload.url, {method: "POST", body: form});
  if (!response.ok) throw new Error("Upload failed");
  return asset.id;
}

// Discover availability and validated settings before selecting a model.
const {data: models} = await api("/media/models");
console.log(models.filter(m => m.available));

const imageId = await upload("reference.png", "image/png");
const input = {
  model: "gemini-3.1-flash-image", operation: "image_edit",
  prompt: "Change the background to a bright photography studio.",
  images: [imageId], people: [],
  settings: {resolution: "1K", aspectRatio: "16:9", audio: false, keepAudio: true}
};
const quote = await api("/media/quotes", input);
console.log("Maximum charge in USD:", quote.chargeMicros / 1e6);
// Submit only after your user accepts this quote. Preserve this key on retries.
const idempotencyKey = randomUUID();
let job = await api("/media/jobs", {quoteId: quote.id, input}, {
  "Idempotency-Key": idempotencyKey
});
while (["queued", "submitting", "processing"].includes(job.status)) {
  await new Promise(resolve => setTimeout(resolve, 8000));
  job = await api("/media/jobs/" + job.id);
}
if (job.status === "reconciling") {
  console.log("Do not resubmit: this job is awaiting reconciliation.");
} else if (job.status === "succeeded") {
  console.log(job.outputs); // Temporary download URLs and retention expiry
} else {
  console.log(job.error);
}

Replace people

Upload the source video and one replacement photo per person. Identify each original person by clothing or position. The API binds numbered references to real attachments and translates the prompt for the selected model. Choose 1–4 people within that model’s validated limit. Exact background, identity, or motion preservation is not guaranteed.

json
{
  "model": "kling-video-o1",
  "operation": "replace_people",
  "prompt": "Keep the scene and original camera movement.",
  "video": "SOURCE_VIDEO_ASSET_ID",
  "images": [],
  "people": [
    {
      "image": "PHOTO_1_ASSET_ID",
      "description": "Left foreground person in a striped shirt"
    },
    {
      "image": "PHOTO_2_ASSET_ID",
      "description": "Right foreground person wearing orange"
    }
  ],
  "settings": {
    "mode": "pro",
    "aspectRatio": "16:9",
    "audio": false,
    "keepAudio": true
  }
}

Replace the placeholder IDs with real upload IDs, request a quote, and submit it using the same lifecycle above.

Charges, retries, and errors

Prices use integer micro-dollars: 1,000,000 micros = $1. The maximum quoted charge is reserved on submission. A successful job settles once; a confirmed failure releases the reservation. Usage and billing include the model and media quantity. Settings without verified pricing cannot be submitted.

Keep the same Idempotency-Key, quoteId, and input when retrying a submission after a network failure. Reusing the key with different inputs returns 409. A new generation needs a new quote and key. Closing Studio does not cancel a job.

States: queued, submitting, processing, reconciling, succeeded, failed. A reconciling job may already have been accepted, so its reservation stays held while its status is checked. Do not start another generation to recover it. Contact support with the job ID if it remains unresolved.

Errors return {"error":{"code":"…","message":"…"}}: 400 invalid/unsupported input; 401 invalid key; 402 insufficient balance; 404 missing or unowned asset/job; 409 expired/changed/used quote or idempotency conflict; 429 active job limit; 503 unavailable model or infrastructure. A failed generation is represented by the job’s failed status.

Media models and current availability

Only available models with a validated configuration accept quotes. Unverified variants remain listed for discovery and cannot charge your balance. Exact combinations are returned by /media/models; obtain a quote for the total price.

Model IDOperationsAvailability / price
Kling O1kling-video-o1video, video edit, replace peopleValidation pending.
Kling 3 Omnikling-v3-omnivideo, video edit, replace peopleValidation pending.
Kling 2.5.turbokling-v2-5-turbovideoValidation pending.
Kling 2.6kling-v2-6videoValidation pending.
Kling 3kling-v3videoValidation pending.
Kling 3.0 Turbokling-3.0-turbovideoValidation pending.
Kling Motion Controlkling-motion-controlmotionValidation pending.
Kling Omni Imagekling-image-o1image, image editValidation pending.
Seedance 1.0 Prodoubao-seedance-1-0-pro-250528videoValidation pending.
Seedance 1.0 Pro Fastdoubao-seedance-1-0-pro-fast-251015videoValidation pending.
Seedance 1.5 Prodoubao-seedance-1-5-pro-251215videoValidation pending.
Seedance 2.0doubao-seedance-2-0-260128videoValidation pending.
Seedance 2.5doubao-seedance-2-5-260628videoValidation pending.
Veo 3.1veo_3_1videoValidation pending.
Veo 3.1 Fastveo_3_1-fastvideoValidation pending.
Veo 3.1 Referencesveo_3_1-componentsvideoValidation pending.
Wan 2.5-i2v-previewwan2.5-i2v-previewvideoValidation pending.
Wan 2.6-i2vwan2.6-i2vvideoValidation pending.
Wan 3.0-videowan3.0-videovideoValidation pending.
Wan 2.7 Image Prowan2.7-image-proimage, image editValidation pending.
Grok Imagine Videogrok-imagine-videovideo, video editValidation pending.
Grok Imagine Video 1.5 Previewgrok-imagine-video-1.5-previewvideoValidation pending.
Grok imagine imagegrok-imagine-imageimage, image editValidation pending.
Grok imagine image qualitygrok-imagine-image-qualityimage, image editValidation pending.
Grok imagine image 2.0grok-imagine-image-2.0image, image editValidation pending.
Nano Bananagemini-2.5-flash-imageimage, image editValidation pending.
Nano Banana Progemini-3-pro-imageimage, image editValidation pending.
Nano Banana Pro Previewgemini-3-pro-image-previewimage, image editValidation pending.
Nano Banana 2gemini-3.1-flash-imageimage, image editValidation pending.
Nano Banana 2 Previewgemini-3.1-flash-image-previewimage, image editValidation pending.
Nano Banana Litegemini-3.1-flash-lite-imageimage, image editValidation pending.
Seedream 3doubao-seedream-3-0-t2i-250415imageValidation pending.
Seedream 4doubao-seedream-4-0-250828image, image editValidation pending.
Seedream 4.5doubao-seedream-4-5-251128image, image editValidation pending.
Seedream 5 Litedoubao-seedream-5-0-260128image, image editValidation pending.
Seedream 5 Prodoubao-seedream-5-0-pro-260628image, image editValidation pending.
Google Omniomni-flashPending availabilityNot currently available.
Sora 2sora-2Pending availabilityNot currently available.
Sora 2 Prosora-2-proPending availabilityNot currently available.
Open Studio →