Media

Generate images, video, and audio from a catalog of hosted models, and ask questions about media you supply — outputs arrive as signed artifact URLs.

Media is a CoreSpeed-hosted capability: no third-party account to connect, and the same /mcp seam as everything else, so identity, organization holds, API-key caps, activity recording, and capability visibility all apply. It has two halves — generation from a catalog of more than a thousand image, video, and audio models, and understanding, which answers a question about a video, image, or audio file you point it at.

Eight tools

ToolUse it for
media__list_modelsSearch the generation catalog with credit rates. No arguments returns the featured picks.
media__get_modelOne model's input schema, vendor, and current rate. Call it before generating.
media__generateRun a model. Waits inline up to wait_seconds, otherwise hands back a running job.
media__get_resultA job's outcome: fresh signed URLs for a finished job, or its current status.
media__list_jobsThis organization's recent jobs, running and finished. Receipts are kept about 30 days.
media__cancelStop a running job. Canceled jobs are never charged.
media__create_uploadMint a one-use upload URL for a local or private file.
media__understandAsk a question about a video, image, or audio file and get a text answer.

Generate: pick a model, then run it

media__list_models

search by name, kind (image · video · audio) or exact category

choose a model id
media__get_model

read input_schema and the structured price

build input against the schema
media__generate

files back inline, or a job_id that finishes server-side

the schema and the rate both come from the catalog, never from the client

input is validated against the model's own input_schema. Unknown top-level keys are rejected — the schema's properties are the allowlist — and safety parameters are policy, not input: whatever the caller sends for a safety*, nsfw*, or moderation* key is discarded and the safe value is enforced on the server. When the upstream model rejects an input anyway, its own validation detail is returned to you, unbilled.

File-typed inputs accept three sources:

  • a public https URL fetchable without authentication;
  • a cs_file_* upload handle from media__create_upload (below);
  • an art_* artifact id from an earlier generation — so image → video chains stay entirely inside CoreSpeed.

A model needs a rate before it can run

price in the catalog is structured, and it is a rate, not a total:

{ "state": "priced", "credits_per_unit": 4, "unit": "image" }

{ "state": "unavailable" } carries no rate fields and means there is no rate right now. Generation is refused (pricing_unavailable, retryable) rather than billed blind — retry shortly.

Long generations become jobs

wait_seconds (default 45, max 300) is the time budget for the whole call. The server answers inside it, one of two ways:

finished inside the budget
{
  "model": "fal-ai/flux/schnell",
  "kind": "image",
  "job_id": "job_…",
  "status": "succeeded",
  "assets": [
    {
      "id": "art_…",
      "mimeType": "image/png",
      "size": 1284021,
      "uri": "https://api.corespeed.io/artifacts/…",
      "expiresAt": "2026-09-10T14:02:11.000Z",
      "width": 1024,
      "height": 1024
    }
  ]
}
still running
{ "job_id": "job_…", "status": "running", "model": "fal-ai/kling-video/v2" }

A running job keeps going on the server for up to 60 minutes, then expires unbilled. Collect it with media__get_result from any session — any agent in the organization can pick up a job another one started — and pass wait_seconds there to long-poll instead of spinning.

Three rules keep this from costing you twice:

  • Do not set a client-side tool timeout equal to or below wait_seconds. That kills the very reply carrying your job_id. Disable the timeout for this call, or set a backstop of at least twice wait_seconds.
  • If the client timed out anyway, nothing is lost. The newest entry in media__list_jobs is your job. Do not resubmit.
  • Signed URLs expire after 12 hours. Call media__get_result again for a fresh set; the stored artifact does not go anywhere.

Job states are running, succeeded, failed, canceled, and expired. A terminal failure comes back as a tool-level error with generation_failed (or the upstream's own code, and its reason when it gave one), generation_canceled, or generation_expired; an unknown id answers job_not_found.

Understand: ask about a file

media__understand takes a prompt and one media source — a public https URL, a YouTube watch URL, or a cs_file_* upload handle. mime_type is inferred from the URL extension or carried by the upload handle.

  • Video can be windowed with start_seconds / end_seconds. max_cost_credits converts a credit budget into a window at the per-second rate; it bounds the media input only, and an explicit end_seconds overrides it. Video is sampled at one frame per second, so fast action between frames can be missed, and timestamps stated in the answer are not guaranteed exact.
  • Audio and images reject all three window parameters, because clipping cannot be enforced for them. The whole file is analysed up to the capability's context limit.

The result carries analyzed_seconds (an estimate — a paging hint, not a duration), truncated when the answer was cut at the output limit, and usage with the metered quantities the call settled for.

Upload a private file

For a file that only exists on local disk:

  1. Call media__create_upload with the exact mime_type and size_bytes. The result includes file_uri (a cs_file_* handle), upload_url, the PUT method, the headers to send — including Authorization — and expires_at.
  2. PUT the raw bytes to upload_url with every returned header, within 10 minutes. The ticket is one-use, and the declared type and size are bound to it.
  3. Use file_uri with media__understand or any file-typed media__generate input. The handle stays valid for 48 hours.

Files up to 2 GB are accepted. A deployment edge may still reject a very large body with HTTP 413; treat that as non-retryable for the deployment rather than retrying the same upload.

Pricing and holds

  • Generation is billed once, after success, at the model's rate times the usage the upstream actually reports. For calls whose size is only known afterwards, the final amount can differ from the rate card. Failures, cancels, and expiries never charge. For expensive kinds — video especially — check media__get_model first.
  • Understanding bills 0.5 credits per image (an oversized image counts as several), 12 credits per minute of video and 4.2 per minute of audio, both metered per second, plus about 1.1 credits per 100 answer tokens. The question itself is free. Failures never charge.

The live figures are in the tool descriptions your client shows from tools/list and in each model's price. Every charge lands itemized in the organization ledger; see Billing & credits. An organization billing hold or suspension stops a media call before it runs — as an isError result with payment_required or org_suspended — and API-key spend caps apply the same way.

Inspect in the dashboard

Dashboard → Media shows everything the organization generated. Running jobs finish server-side and land there whichever agent started them. Turning the capability off in Capability controls hides the media__* tools from tools/list; stored artifacts and job receipts are unaffected.