ESC
Type to search across all documentation
POST

/generate/t2v

202 Accepted

Generate a video directly from a text prompt. MagiCoal first synthesizes a keyframe image using FLUX (2 credits), then animates it with Wan2.2 (50 credits) — totaling 52 credits per generation. Like all generation endpoints, this returns immediately with a UUID for async polling.

Two-stage generation — 52 credits total

Text-to-video generates a FLUX image first (2 cr), then passes it through the Wan2.2 animation pipeline (50 cr). Both stages are billed upfront when the job is submitted. The status endpoint exposes both stages via the stage field.

Endpoint

POST  https://coals.ai/api/v1/magicoal/generate/t2v

Request Body Parameters

Parameter Type Required Description
prompt string required Text description of the video to generate. Max 2000 characters. Used for both the FLUX image synthesis and the Wan2.2 animation pass — describe both the scene and its motion.
num_frames integer optional Number of frames to generate. Range: 17–161. Defaults to 81 (approx. 5 seconds at 16 fps). Use 161 for ~10 seconds.
guidance_scale number optional Classifier-free guidance scale applied during the animation stage. Range: 1.0–10.0. Default: 3.5.
seed integer optional Random seed for reproducibility across both stages. Omit for a random seed.

Prompt tip: Write prompts that describe both the visual scene and the motion. For example: "a lone lighthouse on rocky cliffs at dusk, waves crashing, slow dramatic zoom out" works better than a description with no motion cues.

Request Body

{
  "prompt": "a lone lighthouse on rocky cliffs at dusk, waves crashing below, slow dramatic zoom out, cinematic",
  "num_frames": 81,
  "guidance_scale": 3.5
}

Response — 202 Accepted

{
  "success": true,
  "data": {
    "uuid": "7c4b9e2a-1d8f-4a3e-9b5c-2e6f8d0a4b7c",
    "type": "t2v",
    "status": "queued",
    "credits_charged": 52.0
  }
}
Field Description
uuid Unique job identifier. Pass this to GET /status/{uuid} to track progress.
type Always "t2v" for text-to-video jobs.
status Initial status is "queued". Will progress through "generating_image", "generating_video", then "completed" or "failed".
credits_charged 52 credits (2 for FLUX image + 50 for animation). Refunded automatically if generation fails.
curl -X POST https://coals.ai/api/v1/magicoal/generate/t2v \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "prompt": "a lone lighthouse on rocky cliffs at dusk, waves crashing below, slow dramatic zoom out, cinematic",
    "num_frames": 81,
    "guidance_scale": 3.5
}'
// Using Guzzle
$response = $client->post('https://coals.ai/api/v1/magicoal/generate/t2v', [
  'headers' => ['Authorization' => 'Bearer YOUR_API_KEY'],
  'json' => [
    "prompt" => "a lone lighthouse on rocky cliffs at dusk, waves crashing below, slow dramatic zoom out, cinematic",
    "num_frames" => 81,
    "guidance_scale" => 3.5
]
]);
$data = json_decode($response->getBody(), true);
# Using requests
import requests

response = requests.post(
  "https://coals.ai/api/v1/magicoal/generate/t2v",
  headers={"Authorization": "Bearer YOUR_API_KEY"},
  json={
    "prompt": "a lone lighthouse on rocky cliffs at dusk, waves crashing below, slow dramatic zoom out, cinematic",
    "num_frames": 81,
    "guidance_scale": 3.5
}
)
data = response.json()
# Using net/http
require "net/http"
require "json"

uri = URI("https://coals.ai/api/v1/magicoal/generate/t2v")
req = Net::HTTP::Post.new(uri)
req["Authorization"] = "Bearer YOUR_API_KEY"
req["Content-Type"] = "application/json"
req.body = '{
    "prompt": "a lone lighthouse on rocky cliffs at dusk, waves crashing below, slow dramatic zoom out, cinematic",
    "num_frames": 81,
    "guidance_scale": 3.5
}'

res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)
// Using fetch (Node 18+)
const response = await fetch("https://coals.ai/api/v1/magicoal/generate/t2v", {
  method: "POST",
  headers: {
    "Authorization": "Bearer YOUR_API_KEY",
    "Content-Type": "application/json"
  },
  body: JSON.stringify({
    "prompt": "a lone lighthouse on rocky cliffs at dusk, waves crashing below, slow dramatic zoom out, cinematic",
    "num_frames": 81,
    "guidance_scale": 3.5
})
});
const data = await response.json();