[{"data":1,"prerenderedAt":11288},["ShallowReactive",2],{"blog-/blog/seedance-2-api-tutorial-python":3},{"id":4,"title":5,"body":6,"description":11277,"extension":11278,"meta":11279,"navigation":57,"path":11284,"seo":11285,"stem":11286,"__hash__":11287},"content/en/blog/seedance-2-api-tutorial-python.md","Seedance 2.0 API Tutorial: From Zero to Your First AI Video (Python)",{"type":7,"value":8,"toc":11219},"minimark",[9,13,16,31,43,46,51,54,65,68,90,95,123,126,199,201,205,214,217,245,248,269,288,297,305,307,311,314,328,335,469,472,508,511,1026,1029,1065,1239,1249,1252,1260,1262,1266,1269,1735,1738,1827,1830,1842,1846,1853,2031,2034,2155,2169,2173,2179,2187,2190,2198,2205,2212,2214,2218,2225,2261,2264,2268,2274,2344,2348,2354,2360,2421,2433,2437,2440,2566,2580,2587,2597,2599,2603,2615,2621,2884,2887,2936,2940,2967,2970,3052,3055,3207,3213,3217,3271,3281,3289,3293,3296,3375,3382,3384,3388,3391,3611,3638,3642,3647,3651,3742,3750,3755,3850,3857,3862,3950,3955,4030,4047,4051,4054,4125,4138,4156,4158,4162,4165,4169,4172,4230,4252,4255,4260,4303,4309,4314,4368,4373,4378,4430,4440,4445,4497,4514,4519,4562,4568,4573,4627,4633,4638,4681,4684,4689,4732,4735,4740,4794,4800,4804,5014,5018,5021,5025,5784,5787,5819,5826,5830,5833,6413,6424,6426,6430,6437,6441,6447,6452,6610,6616,6620,6682,6686,6689,7879,7882,7905,7908,7936,7940,7949,7997,8000,8006,8012,8059,8074,8078,8081,8253,8257,8337,8344,8346,8350,8353,8358,8906,8909,8931,8933,8937,8940,8944,8984,8988,9010,9014,9017,9049,9059,9061,9065,9069,9075,9079,9085,9089,9095,9099,9110,9114,9128,9132,9142,9146,9161,9165,9172,9176,9192,9196,9204,9206,9210,9213,11193,11207,11215],[10,11,12],"p",{},"Seedance 2.0 is ByteDance's most advanced AI video model — multimodal references, native audio, cinematic camera control, and 4–15 second generation at up to 1080p. This tutorial walks you through the entire API workflow in Python: from getting your API key to downloading your first generated video.",[10,14,15],{},"By the end, you'll have working code for text-to-video, image-to-video, async polling, webhook handling, and error recovery. Every code example here was tested against a live API.",[17,18,19],"blockquote",{},[10,20,21,25,26,30],{},[22,23,24],"strong",{},"Note — Seedance 2.0 vs 1.5:"," Seedance 2.0 is rolling out progressively. You can test the complete workflow right now using ",[27,28,29],"code",{},"seedance-1.5-pro"," — when 2.0 is fully available, just change the model name. All endpoints, parameters, and response formats are identical. The key differences in 2.0: multimodal references (mix images, videos, and audio as inputs), native audio generation, improved physics simulation, and video editing capabilities. Everything in this tutorial works with both versions.",[10,32,33],{},[22,34,35,42],{},[36,37,41],"a",{"href":38,"rel":39},"https://evolink.ai/early-access",[40],"nofollow","Get your free API key"," to follow along.",[44,45],"hr",{},[47,48,50],"h2",{"id":49},"what-youll-build-and-what-you-need","What You'll Build (and What You Need)",[10,52,53],{},"Here's what a Seedance-generated video looks like — created with a single API call:",[55,56,59,60],"video",{"autoPlay":57,"loop":57,"muted":57,"playsInline":57,"style":58},true,"width:100%;border-radius:12px;margin:1.5em 0","\n  ",[61,62],"source",{"src":63,"type":64},"https://cdn.evolink.ai/seedance2api/%E5%B0%8F%E5%A5%B3%E5%AD%A9%E5%9B%BE%E4%B9%A6%E9%A6%86%E5%A5%87%E9%81%87.mp4","video/mp4",[10,66,67],{},"In this tutorial, you'll write Python code that:",[69,70,71,75,78,81,84,87],"ol",{},[72,73,74],"li",{},"Sends a text prompt → gets back a generated video",[72,76,77],{},"Sends an image → animates it into a video",[72,79,80],{},"Polls for results asynchronously",[72,82,83],{},"Handles errors and retries like production code",[72,85,86],{},"Receives results via webhook (no polling needed)",[72,88,89],{},"Cancels in-progress tasks when needed",[91,92,94],"h3",{"id":93},"prerequisites","Prerequisites",[96,97,98,108,117],"ul",{},[72,99,100,103,104,107],{},[22,101,102],{},"Python 3.8+"," (check with ",[27,105,106],{},"python3 --version",")",[72,109,110,113,114,107],{},[22,111,112],{},"requests"," library (",[27,115,116],{},"pip install requests",[72,118,119,122],{},[22,120,121],{},"An EvoLink API key"," (free to sign up — we'll get this in the next section)",[10,124,125],{},"No GPU, no Docker, no complex setup. Just Python and an API key.",[17,127,128,134],{},[10,129,130,133],{},[22,131,132],{},"Pro Tip:"," If you're building a production app, consider using a virtual environment to isolate dependencies:",[135,136,141],"pre",{"className":137,"code":138,"language":139,"meta":140,"style":140},"language-bash shiki shiki-themes github-dark","python3 -m venv seedance-env\nsource seedance-env/bin/activate  # macOS/Linux\nseedance-env\\Scripts\\activate     # Windows\npip install requests flask\n","bash","",[27,142,143,163,175,184],{"__ignoreMap":140},[144,145,148,152,156,160],"span",{"class":146,"line":147},"line",1,[144,149,151],{"class":150},"svObZ","python3",[144,153,155],{"class":154},"sDLfK"," -m",[144,157,159],{"class":158},"sU2Wk"," venv",[144,161,162],{"class":158}," seedance-env\n",[144,164,166,168,171],{"class":146,"line":165},2,[144,167,61],{"class":154},[144,169,170],{"class":158}," seedance-env/bin/activate",[144,172,174],{"class":173},"sAwPA","  # macOS/Linux\n",[144,176,178,181],{"class":146,"line":177},3,[144,179,180],{"class":150},"seedance-env\\Scripts\\activate",[144,182,183],{"class":173},"     # Windows\n",[144,185,187,190,193,196],{"class":146,"line":186},4,[144,188,189],{"class":150},"pip",[144,191,192],{"class":158}," install",[144,194,195],{"class":158}," requests",[144,197,198],{"class":158}," flask\n",[44,200],{},[47,202,204],{"id":203},"get-your-api-key","Get Your API Key",[10,206,207,208,213],{},"Seedance 2.0 is available through ",[36,209,212],{"href":210,"rel":211},"https://evolink.ai",[40],"EvoLink",", an API gateway that provides unified access to multiple AI video models — including Seedance 2.0, Kling, and others — through a single API key.",[10,215,216],{},"Here's how to get started:",[69,218,219,227,233,239],{},[72,220,221,222,226],{},"Go to ",[36,223,225],{"href":38,"rel":224},[40],"evolink.ai/early-access"," and create an account",[72,228,229,230],{},"Navigate to ",[22,231,232],{},"Dashboard → API Keys",[72,234,235,236],{},"Click ",[22,237,238],{},"Create New Key",[72,240,241,242],{},"Copy your key — it starts with ",[27,243,244],{},"sk-",[10,246,247],{},"Store your key securely. Don't commit it to version control. We'll use an environment variable:",[135,249,251],{"className":137,"code":250,"language":139,"meta":140,"style":140},"export EVOLINK_API_KEY=\"sk-your-api-key-here\"\n",[27,252,253],{"__ignoreMap":140},[144,254,255,259,263,266],{"class":146,"line":147},[144,256,258],{"class":257},"snl16","export",[144,260,262],{"class":261},"s95oV"," EVOLINK_API_KEY",[144,264,265],{"class":257},"=",[144,267,268],{"class":158},"\"sk-your-api-key-here\"\n",[10,270,271,272,275,276,279,280,283,284,287],{},"This line sets the ",[27,273,274],{},"EVOLINK_API_KEY"," environment variable in your terminal session. On macOS/Linux, add it to your ",[27,277,278],{},"~/.bashrc"," or ",[27,281,282],{},"~/.zshrc"," to persist across sessions. On Windows, use ",[27,285,286],{},"set EVOLINK_API_KEY=sk-your-api-key-here"," in Command Prompt, or set it in System Properties → Environment Variables for persistence.",[10,289,290,291,296],{},"Your account includes starter credits to experiment with. Check the ",[36,292,295],{"href":293,"rel":294},"https://seedance2api.app/docs/getting-started",[40],"Getting Started docs"," for current pricing details.",[17,298,299],{},[10,300,301,304],{},[22,302,303],{},"Common Mistake:"," Don't hardcode your API key in source files. If you push it to GitHub, automated scrapers will find it within minutes. Always use environment variables or a secrets manager like AWS Secrets Manager or HashiCorp Vault.",[44,306],{},[47,308,310],{"id":309},"set-up-your-python-environment","Set Up Your Python Environment",[10,312,313],{},"Install the one dependency you need:",[135,315,317],{"className":137,"code":316,"language":139,"meta":140,"style":140},"pip install requests\n",[27,318,319],{"__ignoreMap":140},[144,320,321,323,325],{"class":146,"line":147},[144,322,189],{"class":150},[144,324,192],{"class":158},[144,326,327],{"class":158}," requests\n",[10,329,330,331,334],{},"Create a file called ",[27,332,333],{},"seedance_tutorial.py"," and add this setup code. Every example in this tutorial builds on this foundation:",[135,336,340],{"className":337,"code":338,"language":339,"meta":140,"style":140},"language-python shiki shiki-themes github-dark","import requests\nimport time\nimport os\nimport json\n\n# ── Configuration ─────────────────────────────────────────────\nAPI_KEY = os.getenv(\"EVOLINK_API_KEY\", \"sk-your-api-key-here\")\nBASE_URL = \"https://api.evolink.ai/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {API_KEY}\",\n    \"Content-Type\": \"application/json\"\n}\n","python",[27,341,342,349,356,363,370,376,382,406,417,428,452,463],{"__ignoreMap":140},[144,343,344,347],{"class":146,"line":147},[144,345,346],{"class":257},"import",[144,348,327],{"class":261},[144,350,351,353],{"class":146,"line":165},[144,352,346],{"class":257},[144,354,355],{"class":261}," time\n",[144,357,358,360],{"class":146,"line":177},[144,359,346],{"class":257},[144,361,362],{"class":261}," os\n",[144,364,365,367],{"class":146,"line":186},[144,366,346],{"class":257},[144,368,369],{"class":261}," json\n",[144,371,373],{"class":146,"line":372},5,[144,374,375],{"emptyLinePlaceholder":57},"\n",[144,377,379],{"class":146,"line":378},6,[144,380,381],{"class":173},"# ── Configuration ─────────────────────────────────────────────\n",[144,383,385,388,391,394,397,400,403],{"class":146,"line":384},7,[144,386,387],{"class":154},"API_KEY",[144,389,390],{"class":257}," =",[144,392,393],{"class":261}," os.getenv(",[144,395,396],{"class":158},"\"EVOLINK_API_KEY\"",[144,398,399],{"class":261},", ",[144,401,402],{"class":158},"\"sk-your-api-key-here\"",[144,404,405],{"class":261},")\n",[144,407,409,412,414],{"class":146,"line":408},8,[144,410,411],{"class":154},"BASE_URL",[144,413,390],{"class":257},[144,415,416],{"class":158}," \"https://api.evolink.ai/v1\"\n",[144,418,420,423,425],{"class":146,"line":419},9,[144,421,422],{"class":154},"HEADERS",[144,424,390],{"class":257},[144,426,427],{"class":261}," {\n",[144,429,431,434,437,440,443,446,449],{"class":146,"line":430},10,[144,432,433],{"class":158},"    \"Authorization\"",[144,435,436],{"class":261},": ",[144,438,439],{"class":257},"f",[144,441,442],{"class":158},"\"Bearer ",[144,444,445],{"class":154},"{API_KEY}",[144,447,448],{"class":158},"\"",[144,450,451],{"class":261},",\n",[144,453,455,458,460],{"class":146,"line":454},11,[144,456,457],{"class":158},"    \"Content-Type\"",[144,459,436],{"class":261},[144,461,462],{"class":158},"\"application/json\"\n",[144,464,466],{"class":146,"line":465},12,[144,467,468],{"class":261},"}\n",[10,470,471],{},"Let's break this down line by line:",[96,473,474,482,493],{},[72,475,476,481],{},[22,477,478],{},[27,479,480],{},"os.getenv(\"EVOLINK_API_KEY\", \"sk-your-api-key-here\")"," — Reads the API key from the environment variable. The second argument is a fallback default (replace this with your actual key only for local testing).",[72,483,484,488,489,492],{},[22,485,486],{},[27,487,411],{}," — The root URL for all EvoLink API endpoints. All requests go to ",[27,490,491],{},"https://api.evolink.ai/v1/...",".",[72,494,495,499,500,503,504,507],{},[22,496,497],{},[27,498,422],{}," — Two headers sent with every request: ",[27,501,502],{},"Authorization"," carries your API key using the Bearer token scheme, and ",[27,505,506],{},"Content-Type"," tells the server we're sending JSON.",[10,509,510],{},"Now add the reusable helper functions:",[135,512,514],{"className":337,"code":513,"language":339,"meta":140,"style":140},"# ── Reusable Polling Helper ───────────────────────────────────\ndef wait_for_video(task_id, poll_interval=10, timeout=600):\n    \"\"\"\n    Poll a video generation task until it completes or fails.\n    \n    Args:\n        task_id: The task ID returned by the generation endpoint.\n        poll_interval: Seconds between polls (default 10).\n        timeout: Maximum wait time in seconds (default 600).\n    \n    Returns:\n        dict: The completed task response with video URLs.\n    \n    Raises:\n        TimeoutError: If the task doesn't complete within the timeout.\n        RuntimeError: If the task fails.\n    \"\"\"\n    elapsed = 0\n    while elapsed \u003C timeout:\n        # Send GET request to check the task's current status\n        response = requests.get(\n            f\"{BASE_URL}/tasks/{task_id}\",\n            headers=HEADERS\n        )\n        # Raise an exception if the HTTP status code indicates an error\n        response.raise_for_status()\n        task = response.json()\n\n        # Extract status and progress from the response\n        status = task[\"status\"]\n        progress = task.get(\"progress\", 0)\n        print(f\"  [{elapsed}s] Status: {status} | Progress: {progress}%\")\n\n        # Check terminal states\n        if status == \"completed\":\n            return task\n        elif status == \"failed\":\n            error_info = task.get(\"error\", {})\n            raise RuntimeError(\n                f\"Task {task_id} failed: {error_info.get('message', 'Unknown error')}\"\n            )\n\n        # Wait before the next poll\n        time.sleep(poll_interval)\n        elapsed += poll_interval\n\n    raise TimeoutError(f\"Task {task_id} timed out after {timeout}s\")\n",[27,515,516,521,548,553,558,563,568,573,578,583,587,592,597,602,608,614,620,625,636,651,657,668,695,707,713,719,725,736,741,747,764,785,831,836,842,860,869,884,900,912,950,956,961,967,973,985,990],{"__ignoreMap":140},[144,517,518],{"class":146,"line":147},[144,519,520],{"class":173},"# ── Reusable Polling Helper ───────────────────────────────────\n",[144,522,523,526,529,532,534,537,540,542,545],{"class":146,"line":165},[144,524,525],{"class":257},"def",[144,527,528],{"class":150}," wait_for_video",[144,530,531],{"class":261},"(task_id, poll_interval",[144,533,265],{"class":257},[144,535,536],{"class":154},"10",[144,538,539],{"class":261},", timeout",[144,541,265],{"class":257},[144,543,544],{"class":154},"600",[144,546,547],{"class":261},"):\n",[144,549,550],{"class":146,"line":177},[144,551,552],{"class":158},"    \"\"\"\n",[144,554,555],{"class":146,"line":186},[144,556,557],{"class":158},"    Poll a video generation task until it completes or fails.\n",[144,559,560],{"class":146,"line":372},[144,561,562],{"class":158},"    \n",[144,564,565],{"class":146,"line":378},[144,566,567],{"class":158},"    Args:\n",[144,569,570],{"class":146,"line":384},[144,571,572],{"class":158},"        task_id: The task ID returned by the generation endpoint.\n",[144,574,575],{"class":146,"line":408},[144,576,577],{"class":158},"        poll_interval: Seconds between polls (default 10).\n",[144,579,580],{"class":146,"line":419},[144,581,582],{"class":158},"        timeout: Maximum wait time in seconds (default 600).\n",[144,584,585],{"class":146,"line":430},[144,586,562],{"class":158},[144,588,589],{"class":146,"line":454},[144,590,591],{"class":158},"    Returns:\n",[144,593,594],{"class":146,"line":465},[144,595,596],{"class":158},"        dict: The completed task response with video URLs.\n",[144,598,600],{"class":146,"line":599},13,[144,601,562],{"class":158},[144,603,605],{"class":146,"line":604},14,[144,606,607],{"class":158},"    Raises:\n",[144,609,611],{"class":146,"line":610},15,[144,612,613],{"class":158},"        TimeoutError: If the task doesn't complete within the timeout.\n",[144,615,617],{"class":146,"line":616},16,[144,618,619],{"class":158},"        RuntimeError: If the task fails.\n",[144,621,623],{"class":146,"line":622},17,[144,624,552],{"class":158},[144,626,628,631,633],{"class":146,"line":627},18,[144,629,630],{"class":261},"    elapsed ",[144,632,265],{"class":257},[144,634,635],{"class":154}," 0\n",[144,637,639,642,645,648],{"class":146,"line":638},19,[144,640,641],{"class":257},"    while",[144,643,644],{"class":261}," elapsed ",[144,646,647],{"class":257},"\u003C",[144,649,650],{"class":261}," timeout:\n",[144,652,654],{"class":146,"line":653},20,[144,655,656],{"class":173},"        # Send GET request to check the task's current status\n",[144,658,660,663,665],{"class":146,"line":659},21,[144,661,662],{"class":261},"        response ",[144,664,265],{"class":257},[144,666,667],{"class":261}," requests.get(\n",[144,669,671,674,676,679,682,685,688,691,693],{"class":146,"line":670},22,[144,672,673],{"class":257},"            f",[144,675,448],{"class":158},[144,677,678],{"class":154},"{BASE_URL}",[144,680,681],{"class":158},"/tasks/",[144,683,684],{"class":154},"{",[144,686,687],{"class":261},"task_id",[144,689,690],{"class":154},"}",[144,692,448],{"class":158},[144,694,451],{"class":261},[144,696,698,702,704],{"class":146,"line":697},23,[144,699,701],{"class":700},"s9osk","            headers",[144,703,265],{"class":257},[144,705,706],{"class":154},"HEADERS\n",[144,708,710],{"class":146,"line":709},24,[144,711,712],{"class":261},"        )\n",[144,714,716],{"class":146,"line":715},25,[144,717,718],{"class":173},"        # Raise an exception if the HTTP status code indicates an error\n",[144,720,722],{"class":146,"line":721},26,[144,723,724],{"class":261},"        response.raise_for_status()\n",[144,726,728,731,733],{"class":146,"line":727},27,[144,729,730],{"class":261},"        task ",[144,732,265],{"class":257},[144,734,735],{"class":261}," response.json()\n",[144,737,739],{"class":146,"line":738},28,[144,740,375],{"emptyLinePlaceholder":57},[144,742,744],{"class":146,"line":743},29,[144,745,746],{"class":173},"        # Extract status and progress from the response\n",[144,748,750,753,755,758,761],{"class":146,"line":749},30,[144,751,752],{"class":261},"        status ",[144,754,265],{"class":257},[144,756,757],{"class":261}," task[",[144,759,760],{"class":158},"\"status\"",[144,762,763],{"class":261},"]\n",[144,765,767,770,772,775,778,780,783],{"class":146,"line":766},31,[144,768,769],{"class":261},"        progress ",[144,771,265],{"class":257},[144,773,774],{"class":261}," task.get(",[144,776,777],{"class":158},"\"progress\"",[144,779,399],{"class":261},[144,781,782],{"class":154},"0",[144,784,405],{"class":261},[144,786,788,791,794,796,799,801,804,806,809,811,814,816,819,821,824,826,829],{"class":146,"line":787},32,[144,789,790],{"class":154},"        print",[144,792,793],{"class":261},"(",[144,795,439],{"class":257},[144,797,798],{"class":158},"\"  [",[144,800,684],{"class":154},[144,802,803],{"class":261},"elapsed",[144,805,690],{"class":154},[144,807,808],{"class":158},"s] Status: ",[144,810,684],{"class":154},[144,812,813],{"class":261},"status",[144,815,690],{"class":154},[144,817,818],{"class":158}," | Progress: ",[144,820,684],{"class":154},[144,822,823],{"class":261},"progress",[144,825,690],{"class":154},[144,827,828],{"class":158},"%\"",[144,830,405],{"class":261},[144,832,834],{"class":146,"line":833},33,[144,835,375],{"emptyLinePlaceholder":57},[144,837,839],{"class":146,"line":838},34,[144,840,841],{"class":173},"        # Check terminal states\n",[144,843,845,848,851,854,857],{"class":146,"line":844},35,[144,846,847],{"class":257},"        if",[144,849,850],{"class":261}," status ",[144,852,853],{"class":257},"==",[144,855,856],{"class":158}," \"completed\"",[144,858,859],{"class":261},":\n",[144,861,863,866],{"class":146,"line":862},36,[144,864,865],{"class":257},"            return",[144,867,868],{"class":261}," task\n",[144,870,872,875,877,879,882],{"class":146,"line":871},37,[144,873,874],{"class":257},"        elif",[144,876,850],{"class":261},[144,878,853],{"class":257},[144,880,881],{"class":158}," \"failed\"",[144,883,859],{"class":261},[144,885,887,890,892,894,897],{"class":146,"line":886},38,[144,888,889],{"class":261},"            error_info ",[144,891,265],{"class":257},[144,893,774],{"class":261},[144,895,896],{"class":158},"\"error\"",[144,898,899],{"class":261},", {})\n",[144,901,903,906,909],{"class":146,"line":902},39,[144,904,905],{"class":257},"            raise",[144,907,908],{"class":154}," RuntimeError",[144,910,911],{"class":261},"(\n",[144,913,915,918,921,923,925,927,930,932,935,938,940,943,945,947],{"class":146,"line":914},40,[144,916,917],{"class":257},"                f",[144,919,920],{"class":158},"\"Task ",[144,922,684],{"class":154},[144,924,687],{"class":261},[144,926,690],{"class":154},[144,928,929],{"class":158}," failed: ",[144,931,684],{"class":154},[144,933,934],{"class":261},"error_info.get(",[144,936,937],{"class":158},"'message'",[144,939,399],{"class":261},[144,941,942],{"class":158},"'Unknown error'",[144,944,107],{"class":261},[144,946,690],{"class":154},[144,948,949],{"class":158},"\"\n",[144,951,953],{"class":146,"line":952},41,[144,954,955],{"class":261},"            )\n",[144,957,959],{"class":146,"line":958},42,[144,960,375],{"emptyLinePlaceholder":57},[144,962,964],{"class":146,"line":963},43,[144,965,966],{"class":173},"        # Wait before the next poll\n",[144,968,970],{"class":146,"line":969},44,[144,971,972],{"class":261},"        time.sleep(poll_interval)\n",[144,974,976,979,982],{"class":146,"line":975},45,[144,977,978],{"class":261},"        elapsed ",[144,980,981],{"class":257},"+=",[144,983,984],{"class":261}," poll_interval\n",[144,986,988],{"class":146,"line":987},46,[144,989,375],{"emptyLinePlaceholder":57},[144,991,993,996,999,1001,1003,1005,1007,1009,1011,1014,1016,1019,1021,1024],{"class":146,"line":992},47,[144,994,995],{"class":257},"    raise",[144,997,998],{"class":154}," TimeoutError",[144,1000,793],{"class":261},[144,1002,439],{"class":257},[144,1004,920],{"class":158},[144,1006,684],{"class":154},[144,1008,687],{"class":261},[144,1010,690],{"class":154},[144,1012,1013],{"class":158}," timed out after ",[144,1015,684],{"class":154},[144,1017,1018],{"class":261},"timeout",[144,1020,690],{"class":154},[144,1022,1023],{"class":158},"s\"",[144,1025,405],{"class":261},[10,1027,1028],{},"Key design decisions in this function:",[96,1030,1031,1039,1047,1055],{},[72,1032,1033,1038],{},[22,1034,1035],{},[27,1036,1037],{},"poll_interval=10"," — 10 seconds is the sweet spot. Faster wastes API quota; slower delays your workflow.",[72,1040,1041,1046],{},[22,1042,1043],{},[27,1044,1045],{},"timeout=600"," — 10 minutes is generous. Most videos complete in 30–120 seconds, but this covers edge cases like queue congestion.",[72,1048,1049,1054],{},[22,1050,1051],{},[27,1052,1053],{},"response.raise_for_status()"," — Converts HTTP errors (4xx/5xx) into Python exceptions so they don't silently pass.",[72,1056,1057,1060,1061,1064],{},[22,1058,1059],{},"Progress printing"," — The ",[27,1062,1063],{},"[elapsed]s"," prefix helps you correlate timing. Useful for debugging slow generations.",[135,1066,1068],{"className":337,"code":1067,"language":339,"meta":140,"style":140},"# ── Helper: Download Video ────────────────────────────────────\ndef download_video(url, filename=\"output.mp4\"):\n    \"\"\"Download a video file from a URL.\"\"\"\n    print(f\"Downloading video to {filename}...\")\n    resp = requests.get(url, stream=True)\n    resp.raise_for_status()\n    with open(filename, \"wb\") as f:\n        for chunk in resp.iter_content(chunk_size=8192):\n            f.write(chunk)\n    print(f\"Saved: {filename} ({os.path.getsize(filename) / 1024:.0f} KB)\")\n",[27,1069,1070,1075,1092,1097,1121,1141,1146,1169,1193,1198],{"__ignoreMap":140},[144,1071,1072],{"class":146,"line":147},[144,1073,1074],{"class":173},"# ── Helper: Download Video ────────────────────────────────────\n",[144,1076,1077,1079,1082,1085,1087,1090],{"class":146,"line":165},[144,1078,525],{"class":257},[144,1080,1081],{"class":150}," download_video",[144,1083,1084],{"class":261},"(url, filename",[144,1086,265],{"class":257},[144,1088,1089],{"class":158},"\"output.mp4\"",[144,1091,547],{"class":261},[144,1093,1094],{"class":146,"line":177},[144,1095,1096],{"class":158},"    \"\"\"Download a video file from a URL.\"\"\"\n",[144,1098,1099,1102,1104,1106,1109,1111,1114,1116,1119],{"class":146,"line":186},[144,1100,1101],{"class":154},"    print",[144,1103,793],{"class":261},[144,1105,439],{"class":257},[144,1107,1108],{"class":158},"\"Downloading video to ",[144,1110,684],{"class":154},[144,1112,1113],{"class":261},"filename",[144,1115,690],{"class":154},[144,1117,1118],{"class":158},"...\"",[144,1120,405],{"class":261},[144,1122,1123,1126,1128,1131,1134,1136,1139],{"class":146,"line":372},[144,1124,1125],{"class":261},"    resp ",[144,1127,265],{"class":257},[144,1129,1130],{"class":261}," requests.get(url, ",[144,1132,1133],{"class":700},"stream",[144,1135,265],{"class":257},[144,1137,1138],{"class":154},"True",[144,1140,405],{"class":261},[144,1142,1143],{"class":146,"line":378},[144,1144,1145],{"class":261},"    resp.raise_for_status()\n",[144,1147,1148,1151,1154,1157,1160,1163,1166],{"class":146,"line":384},[144,1149,1150],{"class":257},"    with",[144,1152,1153],{"class":154}," open",[144,1155,1156],{"class":261},"(filename, ",[144,1158,1159],{"class":158},"\"wb\"",[144,1161,1162],{"class":261},") ",[144,1164,1165],{"class":257},"as",[144,1167,1168],{"class":261}," f:\n",[144,1170,1171,1174,1177,1180,1183,1186,1188,1191],{"class":146,"line":408},[144,1172,1173],{"class":257},"        for",[144,1175,1176],{"class":261}," chunk ",[144,1178,1179],{"class":257},"in",[144,1181,1182],{"class":261}," resp.iter_content(",[144,1184,1185],{"class":700},"chunk_size",[144,1187,265],{"class":257},[144,1189,1190],{"class":154},"8192",[144,1192,547],{"class":261},[144,1194,1195],{"class":146,"line":419},[144,1196,1197],{"class":261},"            f.write(chunk)\n",[144,1199,1200,1202,1204,1206,1209,1211,1213,1215,1218,1220,1223,1226,1229,1232,1234,1237],{"class":146,"line":430},[144,1201,1101],{"class":154},[144,1203,793],{"class":261},[144,1205,439],{"class":257},[144,1207,1208],{"class":158},"\"Saved: ",[144,1210,684],{"class":154},[144,1212,1113],{"class":261},[144,1214,690],{"class":154},[144,1216,1217],{"class":158}," (",[144,1219,684],{"class":154},[144,1221,1222],{"class":261},"os.path.getsize(filename) ",[144,1224,1225],{"class":257},"/",[144,1227,1228],{"class":154}," 1024",[144,1230,1231],{"class":257},":.0f",[144,1233,690],{"class":154},[144,1235,1236],{"class":158}," KB)\"",[144,1238,405],{"class":261},[10,1240,1241,1242,1245,1246,1248],{},"This function streams the download in 8 KB chunks instead of loading the entire video into memory. This matters — generated videos can be 10–50 MB. The ",[27,1243,1244],{},"stream=True"," parameter tells ",[27,1247,112],{}," to download incrementally.",[10,1250,1251],{},"These three pieces — configuration, polling, and download — are the foundation. Every code example below uses them. We won't repeat them — just the new payload each time.",[10,1253,1254,1255,492],{},"For the full API reference, see the ",[36,1256,1259],{"href":1257,"rel":1258},"https://seedance2api.app/docs/video-generation",[40],"Video Generation docs",[44,1261],{},[47,1263,1265],{"id":1264},"generate-your-first-video-text-to-video","Generate Your First Video (Text-to-Video)",[10,1267,1268],{},"Time to generate a video. Add this to your script:",[135,1270,1272],{"className":337,"code":1271,"language":339,"meta":140,"style":140},"# ── Text-to-Video ─────────────────────────────────────────────\ndef text_to_video():\n    payload = {\n        \"model\": \"seedance-2.0\",          # The AI model to use\n        \"prompt\": (\n            \"A golden retriever puppy chases a butterfly through \"\n            \"a sunlit meadow. The camera follows the puppy with a \"\n            \"smooth tracking shot as wildflowers sway in the breeze.\"\n        ),\n        \"duration\": 5,                     # Video length: 4-15 seconds\n        \"quality\": \"720p\",                 # Resolution: 480p, 720p, 1080p\n        \"aspect_ratio\": \"16:9\",            # Standard widescreen\n        \"generate_audio\": True             # AI generates matching audio\n    }\n\n    print(\"Submitting text-to-video request...\")\n    response = requests.post(\n        f\"{BASE_URL}/videos/generations\",  # The video generation endpoint\n        headers=HEADERS,                   # Auth + content-type headers\n        json=payload                       # Automatically serializes to JSON\n    )\n    response.raise_for_status()            # Throw if not 200 OK\n    task = response.json()                 # Parse the JSON response\n\n    # Log key info from the response\n    print(f\"Task created: {task['id']}\")\n    print(f\"Estimated time: {task['task_info']['estimated_time']}s\")\n    print(f\"Credits reserved: {task['usage']['credits_reserved']}\")\n\n    # Poll until the video is ready\n    result = wait_for_video(task[\"id\"])\n\n    # The results array contains one or more video URLs\n    video_url = result[\"results\"][0]\n    print(f\"\\nVideo URL: {video_url}\")\n    download_video(video_url, \"my_first_video.mp4\")\n\n    return result\n\n\nif __name__ == \"__main__\":\n    text_to_video()\n",[27,1273,1274,1279,1289,1298,1314,1322,1327,1332,1337,1342,1358,1374,1390,1402,1407,1411,1422,1432,1450,1465,1478,1483,1491,1504,1508,1513,1541,1573,1604,1608,1613,1629,1633,1638,1657,1684,1694,1698,1706,1710,1714,1730],{"__ignoreMap":140},[144,1275,1276],{"class":146,"line":147},[144,1277,1278],{"class":173},"# ── Text-to-Video ─────────────────────────────────────────────\n",[144,1280,1281,1283,1286],{"class":146,"line":165},[144,1282,525],{"class":257},[144,1284,1285],{"class":150}," text_to_video",[144,1287,1288],{"class":261},"():\n",[144,1290,1291,1294,1296],{"class":146,"line":177},[144,1292,1293],{"class":261},"    payload ",[144,1295,265],{"class":257},[144,1297,427],{"class":261},[144,1299,1300,1303,1305,1308,1311],{"class":146,"line":186},[144,1301,1302],{"class":158},"        \"model\"",[144,1304,436],{"class":261},[144,1306,1307],{"class":158},"\"seedance-2.0\"",[144,1309,1310],{"class":261},",          ",[144,1312,1313],{"class":173},"# The AI model to use\n",[144,1315,1316,1319],{"class":146,"line":372},[144,1317,1318],{"class":158},"        \"prompt\"",[144,1320,1321],{"class":261},": (\n",[144,1323,1324],{"class":146,"line":378},[144,1325,1326],{"class":158},"            \"A golden retriever puppy chases a butterfly through \"\n",[144,1328,1329],{"class":146,"line":384},[144,1330,1331],{"class":158},"            \"a sunlit meadow. The camera follows the puppy with a \"\n",[144,1333,1334],{"class":146,"line":408},[144,1335,1336],{"class":158},"            \"smooth tracking shot as wildflowers sway in the breeze.\"\n",[144,1338,1339],{"class":146,"line":419},[144,1340,1341],{"class":261},"        ),\n",[144,1343,1344,1347,1349,1352,1355],{"class":146,"line":430},[144,1345,1346],{"class":158},"        \"duration\"",[144,1348,436],{"class":261},[144,1350,1351],{"class":154},"5",[144,1353,1354],{"class":261},",                     ",[144,1356,1357],{"class":173},"# Video length: 4-15 seconds\n",[144,1359,1360,1363,1365,1368,1371],{"class":146,"line":454},[144,1361,1362],{"class":158},"        \"quality\"",[144,1364,436],{"class":261},[144,1366,1367],{"class":158},"\"720p\"",[144,1369,1370],{"class":261},",                 ",[144,1372,1373],{"class":173},"# Resolution: 480p, 720p, 1080p\n",[144,1375,1376,1379,1381,1384,1387],{"class":146,"line":465},[144,1377,1378],{"class":158},"        \"aspect_ratio\"",[144,1380,436],{"class":261},[144,1382,1383],{"class":158},"\"16:9\"",[144,1385,1386],{"class":261},",            ",[144,1388,1389],{"class":173},"# Standard widescreen\n",[144,1391,1392,1395,1397,1399],{"class":146,"line":599},[144,1393,1394],{"class":158},"        \"generate_audio\"",[144,1396,436],{"class":261},[144,1398,1138],{"class":154},[144,1400,1401],{"class":173},"             # AI generates matching audio\n",[144,1403,1404],{"class":146,"line":604},[144,1405,1406],{"class":261},"    }\n",[144,1408,1409],{"class":146,"line":610},[144,1410,375],{"emptyLinePlaceholder":57},[144,1412,1413,1415,1417,1420],{"class":146,"line":616},[144,1414,1101],{"class":154},[144,1416,793],{"class":261},[144,1418,1419],{"class":158},"\"Submitting text-to-video request...\"",[144,1421,405],{"class":261},[144,1423,1424,1427,1429],{"class":146,"line":622},[144,1425,1426],{"class":261},"    response ",[144,1428,265],{"class":257},[144,1430,1431],{"class":261}," requests.post(\n",[144,1433,1434,1437,1439,1441,1444,1447],{"class":146,"line":627},[144,1435,1436],{"class":257},"        f",[144,1438,448],{"class":158},[144,1440,678],{"class":154},[144,1442,1443],{"class":158},"/videos/generations\"",[144,1445,1446],{"class":261},",  ",[144,1448,1449],{"class":173},"# The video generation endpoint\n",[144,1451,1452,1455,1457,1459,1462],{"class":146,"line":638},[144,1453,1454],{"class":700},"        headers",[144,1456,265],{"class":257},[144,1458,422],{"class":154},[144,1460,1461],{"class":261},",                   ",[144,1463,1464],{"class":173},"# Auth + content-type headers\n",[144,1466,1467,1470,1472,1475],{"class":146,"line":653},[144,1468,1469],{"class":700},"        json",[144,1471,265],{"class":257},[144,1473,1474],{"class":261},"payload                       ",[144,1476,1477],{"class":173},"# Automatically serializes to JSON\n",[144,1479,1480],{"class":146,"line":659},[144,1481,1482],{"class":261},"    )\n",[144,1484,1485,1488],{"class":146,"line":670},[144,1486,1487],{"class":261},"    response.raise_for_status()            ",[144,1489,1490],{"class":173},"# Throw if not 200 OK\n",[144,1492,1493,1496,1498,1501],{"class":146,"line":697},[144,1494,1495],{"class":261},"    task ",[144,1497,265],{"class":257},[144,1499,1500],{"class":261}," response.json()                 ",[144,1502,1503],{"class":173},"# Parse the JSON response\n",[144,1505,1506],{"class":146,"line":709},[144,1507,375],{"emptyLinePlaceholder":57},[144,1509,1510],{"class":146,"line":715},[144,1511,1512],{"class":173},"    # Log key info from the response\n",[144,1514,1515,1517,1519,1521,1524,1526,1529,1532,1535,1537,1539],{"class":146,"line":721},[144,1516,1101],{"class":154},[144,1518,793],{"class":261},[144,1520,439],{"class":257},[144,1522,1523],{"class":158},"\"Task created: ",[144,1525,684],{"class":154},[144,1527,1528],{"class":261},"task[",[144,1530,1531],{"class":158},"'id'",[144,1533,1534],{"class":261},"]",[144,1536,690],{"class":154},[144,1538,448],{"class":158},[144,1540,405],{"class":261},[144,1542,1543,1545,1547,1549,1552,1554,1556,1559,1562,1565,1567,1569,1571],{"class":146,"line":727},[144,1544,1101],{"class":154},[144,1546,793],{"class":261},[144,1548,439],{"class":257},[144,1550,1551],{"class":158},"\"Estimated time: ",[144,1553,684],{"class":154},[144,1555,1528],{"class":261},[144,1557,1558],{"class":158},"'task_info'",[144,1560,1561],{"class":261},"][",[144,1563,1564],{"class":158},"'estimated_time'",[144,1566,1534],{"class":261},[144,1568,690],{"class":154},[144,1570,1023],{"class":158},[144,1572,405],{"class":261},[144,1574,1575,1577,1579,1581,1584,1586,1588,1591,1593,1596,1598,1600,1602],{"class":146,"line":738},[144,1576,1101],{"class":154},[144,1578,793],{"class":261},[144,1580,439],{"class":257},[144,1582,1583],{"class":158},"\"Credits reserved: ",[144,1585,684],{"class":154},[144,1587,1528],{"class":261},[144,1589,1590],{"class":158},"'usage'",[144,1592,1561],{"class":261},[144,1594,1595],{"class":158},"'credits_reserved'",[144,1597,1534],{"class":261},[144,1599,690],{"class":154},[144,1601,448],{"class":158},[144,1603,405],{"class":261},[144,1605,1606],{"class":146,"line":743},[144,1607,375],{"emptyLinePlaceholder":57},[144,1609,1610],{"class":146,"line":749},[144,1611,1612],{"class":173},"    # Poll until the video is ready\n",[144,1614,1615,1618,1620,1623,1626],{"class":146,"line":766},[144,1616,1617],{"class":261},"    result ",[144,1619,265],{"class":257},[144,1621,1622],{"class":261}," wait_for_video(task[",[144,1624,1625],{"class":158},"\"id\"",[144,1627,1628],{"class":261},"])\n",[144,1630,1631],{"class":146,"line":787},[144,1632,375],{"emptyLinePlaceholder":57},[144,1634,1635],{"class":146,"line":833},[144,1636,1637],{"class":173},"    # The results array contains one or more video URLs\n",[144,1639,1640,1643,1645,1648,1651,1653,1655],{"class":146,"line":838},[144,1641,1642],{"class":261},"    video_url ",[144,1644,265],{"class":257},[144,1646,1647],{"class":261}," result[",[144,1649,1650],{"class":158},"\"results\"",[144,1652,1561],{"class":261},[144,1654,782],{"class":154},[144,1656,763],{"class":261},[144,1658,1659,1661,1663,1665,1667,1670,1673,1675,1678,1680,1682],{"class":146,"line":844},[144,1660,1101],{"class":154},[144,1662,793],{"class":261},[144,1664,439],{"class":257},[144,1666,448],{"class":158},[144,1668,1669],{"class":154},"\\n",[144,1671,1672],{"class":158},"Video URL: ",[144,1674,684],{"class":154},[144,1676,1677],{"class":261},"video_url",[144,1679,690],{"class":154},[144,1681,448],{"class":158},[144,1683,405],{"class":261},[144,1685,1686,1689,1692],{"class":146,"line":862},[144,1687,1688],{"class":261},"    download_video(video_url, ",[144,1690,1691],{"class":158},"\"my_first_video.mp4\"",[144,1693,405],{"class":261},[144,1695,1696],{"class":146,"line":871},[144,1697,375],{"emptyLinePlaceholder":57},[144,1699,1700,1703],{"class":146,"line":886},[144,1701,1702],{"class":257},"    return",[144,1704,1705],{"class":261}," result\n",[144,1707,1708],{"class":146,"line":902},[144,1709,375],{"emptyLinePlaceholder":57},[144,1711,1712],{"class":146,"line":914},[144,1713,375],{"emptyLinePlaceholder":57},[144,1715,1716,1719,1722,1725,1728],{"class":146,"line":952},[144,1717,1718],{"class":257},"if",[144,1720,1721],{"class":154}," __name__",[144,1723,1724],{"class":257}," ==",[144,1726,1727],{"class":158}," \"__main__\"",[144,1729,859],{"class":261},[144,1731,1732],{"class":146,"line":958},[144,1733,1734],{"class":261},"    text_to_video()\n",[10,1736,1737],{},"Let's walk through each parameter in the payload:",[96,1739,1740,1755,1767,1775,1795,1815],{},[72,1741,1742,1747,1748,1751,1752,1754],{},[22,1743,1744],{},[27,1745,1746],{},"model"," — Which Seedance model to use. Set ",[27,1749,1750],{},"seedance-2.0"," for the latest; use ",[27,1753,29],{}," if 2.0 isn't available in your region yet.",[72,1756,1757,1762,1763,492],{},[22,1758,1759],{},[27,1760,1761],{},"prompt"," — Your video description. Be specific about subject, action, camera movement, and mood. The prompt above uses a three-part structure: subject (\"golden retriever puppy\"), action (\"chases a butterfly\"), and camera (\"smooth tracking shot\"). For advanced prompt techniques, see our ",[36,1764,1766],{"href":1765},"/blog/seedance-2-prompt-guide","Prompt Engineering Guide",[72,1768,1769,1774],{},[22,1770,1771],{},[27,1772,1773],{},"duration"," — Video length in seconds (4–15). Shorter videos generate faster and cost fewer credits. Start with 5 for testing.",[72,1776,1777,1782,1783,1786,1787,1790,1791,1794],{},[22,1778,1779],{},[27,1780,1781],{},"quality"," — Resolution tier. ",[27,1784,1785],{},"720p"," is the best balance of quality and speed for development. Use ",[27,1788,1789],{},"480p"," for rapid iteration, ",[27,1792,1793],{},"1080p"," for final renders.",[72,1796,1797,1802,1803,1806,1807,1810,1811,1814],{},[22,1798,1799],{},[27,1800,1801],{},"aspect_ratio"," — Output dimensions. ",[27,1804,1805],{},"16:9"," for YouTube/landscape, ",[27,1808,1809],{},"9:16"," for TikTok/Reels/Shorts, ",[27,1812,1813],{},"1:1"," for Instagram feed.",[72,1816,1817,1822,1823,1826],{},[22,1818,1819],{},[27,1820,1821],{},"generate_audio"," — When ",[27,1824,1825],{},"true",", Seedance generates ambient sound and music that matches the visual content. Adds ~2 seconds to generation time.",[10,1828,1829],{},"Run it:",[135,1831,1833],{"className":137,"code":1832,"language":139,"meta":140,"style":140},"python seedance_tutorial.py\n",[27,1834,1835],{"__ignoreMap":140},[144,1836,1837,1839],{"class":146,"line":147},[144,1838,339],{"class":150},[144,1840,1841],{"class":158}," seedance_tutorial.py\n",[91,1843,1845],{"id":1844},"what-the-api-returns","What the API Returns",[10,1847,1848,1849,1852],{},"When you submit a generation request, you get back a ",[22,1850,1851],{},"task object"," immediately — the video isn't ready yet. Here's the actual response:",[135,1854,1858],{"className":1855,"code":1856,"language":1857,"meta":140,"style":140},"language-json shiki shiki-themes github-dark","{\n  \"created\": 1772203771,\n  \"id\": \"task-unified-1772203771-yf1dxogh\",\n  \"model\": \"seedance-2.0\",\n  \"object\": \"video.generation.task\",\n  \"progress\": 0,\n  \"status\": \"pending\",\n  \"task_info\": {\n    \"can_cancel\": true,\n    \"estimated_time\": 132\n  },\n  \"type\": \"video\",\n  \"usage\": {\n    \"billing_rule\": \"per_second\",\n    \"credits_reserved\": 17.784,\n    \"user_group\": \"default\"\n  }\n}\n","json",[27,1859,1860,1865,1877,1889,1900,1912,1923,1935,1943,1954,1964,1969,1981,1988,2000,2012,2022,2027],{"__ignoreMap":140},[144,1861,1862],{"class":146,"line":147},[144,1863,1864],{"class":261},"{\n",[144,1866,1867,1870,1872,1875],{"class":146,"line":165},[144,1868,1869],{"class":154},"  \"created\"",[144,1871,436],{"class":261},[144,1873,1874],{"class":154},"1772203771",[144,1876,451],{"class":261},[144,1878,1879,1882,1884,1887],{"class":146,"line":177},[144,1880,1881],{"class":154},"  \"id\"",[144,1883,436],{"class":261},[144,1885,1886],{"class":158},"\"task-unified-1772203771-yf1dxogh\"",[144,1888,451],{"class":261},[144,1890,1891,1894,1896,1898],{"class":146,"line":186},[144,1892,1893],{"class":154},"  \"model\"",[144,1895,436],{"class":261},[144,1897,1307],{"class":158},[144,1899,451],{"class":261},[144,1901,1902,1905,1907,1910],{"class":146,"line":372},[144,1903,1904],{"class":154},"  \"object\"",[144,1906,436],{"class":261},[144,1908,1909],{"class":158},"\"video.generation.task\"",[144,1911,451],{"class":261},[144,1913,1914,1917,1919,1921],{"class":146,"line":378},[144,1915,1916],{"class":154},"  \"progress\"",[144,1918,436],{"class":261},[144,1920,782],{"class":154},[144,1922,451],{"class":261},[144,1924,1925,1928,1930,1933],{"class":146,"line":384},[144,1926,1927],{"class":154},"  \"status\"",[144,1929,436],{"class":261},[144,1931,1932],{"class":158},"\"pending\"",[144,1934,451],{"class":261},[144,1936,1937,1940],{"class":146,"line":408},[144,1938,1939],{"class":154},"  \"task_info\"",[144,1941,1942],{"class":261},": {\n",[144,1944,1945,1948,1950,1952],{"class":146,"line":419},[144,1946,1947],{"class":154},"    \"can_cancel\"",[144,1949,436],{"class":261},[144,1951,1825],{"class":154},[144,1953,451],{"class":261},[144,1955,1956,1959,1961],{"class":146,"line":430},[144,1957,1958],{"class":154},"    \"estimated_time\"",[144,1960,436],{"class":261},[144,1962,1963],{"class":154},"132\n",[144,1965,1966],{"class":146,"line":454},[144,1967,1968],{"class":261},"  },\n",[144,1970,1971,1974,1976,1979],{"class":146,"line":465},[144,1972,1973],{"class":154},"  \"type\"",[144,1975,436],{"class":261},[144,1977,1978],{"class":158},"\"video\"",[144,1980,451],{"class":261},[144,1982,1983,1986],{"class":146,"line":599},[144,1984,1985],{"class":154},"  \"usage\"",[144,1987,1942],{"class":261},[144,1989,1990,1993,1995,1998],{"class":146,"line":604},[144,1991,1992],{"class":154},"    \"billing_rule\"",[144,1994,436],{"class":261},[144,1996,1997],{"class":158},"\"per_second\"",[144,1999,451],{"class":261},[144,2001,2002,2005,2007,2010],{"class":146,"line":610},[144,2003,2004],{"class":154},"    \"credits_reserved\"",[144,2006,436],{"class":261},[144,2008,2009],{"class":154},"17.784",[144,2011,451],{"class":261},[144,2013,2014,2017,2019],{"class":146,"line":616},[144,2015,2016],{"class":154},"    \"user_group\"",[144,2018,436],{"class":261},[144,2020,2021],{"class":158},"\"default\"\n",[144,2023,2024],{"class":146,"line":622},[144,2025,2026],{"class":261},"  }\n",[144,2028,2029],{"class":146,"line":627},[144,2030,468],{"class":261},[10,2032,2033],{},"Key fields explained:",[2035,2036,2037,2050],"table",{},[2038,2039,2040],"thead",{},[2041,2042,2043,2047],"tr",{},[2044,2045,2046],"th",{},"Field",[2044,2048,2049],{},"Meaning",[2051,2052,2053,2064,2087,2098,2108,2118,2131,2141],"tbody",{},[2041,2054,2055,2061],{},[2056,2057,2058],"td",{},[27,2059,2060],{},"id",[2056,2062,2063],{},"Your task ID — use this to check status and retrieve results",[2041,2065,2066,2070],{},[2056,2067,2068],{},[27,2069,813],{},[2056,2071,2072,2073,2076,2077,2080,2081,279,2084],{},"Starts as ",[27,2074,2075],{},"pending",", moves to ",[27,2078,2079],{},"processing",", then ",[27,2082,2083],{},"completed",[27,2085,2086],{},"failed",[2041,2088,2089,2093],{},[2056,2090,2091],{},[27,2092,823],{},[2056,2094,2095,2096],{},"0–100 percentage. Updates in real-time during ",[27,2097,2079],{},[2041,2099,2100,2105],{},[2056,2101,2102],{},[27,2103,2104],{},"estimated_time",[2056,2106,2107],{},"Approximate seconds until completion (server-side estimate)",[2041,2109,2110,2115],{},[2056,2111,2112],{},[27,2113,2114],{},"credits_reserved",[2056,2116,2117],{},"Credits held for this job. Refunded automatically if the task fails",[2041,2119,2120,2125],{},[2056,2121,2122],{},[27,2123,2124],{},"task_info.can_cancel",[2056,2126,2127,2128,2130],{},"Whether you can cancel this task (always ",[27,2129,1825],{}," before completion)",[2041,2132,2133,2138],{},[2056,2134,2135],{},[27,2136,2137],{},"created",[2056,2139,2140],{},"Unix timestamp of when the task was submitted",[2041,2142,2143,2148],{},[2056,2144,2145],{},[27,2146,2147],{},"usage.billing_rule",[2056,2149,2150,2151,2154],{},"How credits are calculated — ",[27,2152,2153],{},"per_second"," means cost scales with duration",[17,2156,2157],{},[10,2158,2159,2161,2162,2164,2165,2168],{},[22,2160,132],{}," Save the ",[27,2163,2060],{}," to a file or database immediately after submission. If your script crashes during polling, you can resume by calling ",[27,2166,2167],{},"wait_for_video()"," with the saved task ID. Tasks persist on the server for 24 hours.",[91,2170,2172],{"id":2171},"the-polling-sequence","The Polling Sequence",[10,2174,2175,2176,2178],{},"The ",[27,2177,2167],{}," function polls every 10 seconds. Here's what the real output looks like:",[135,2180,2185],{"className":2181,"code":2183,"language":2184},[2182],"language-text","Submitting text-to-video request...\nTask created: task-unified-1772203771-yf1dxogh\nEstimated time: 132s\nCredits reserved: 17.784\n  [0s] Status: pending | Progress: 0%\n  [10s] Status: processing | Progress: 7%\n  [20s] Status: processing | Progress: 13%\n  [30s] Status: processing | Progress: 20%\n  [40s] Status: processing | Progress: 27%\n  [50s] Status: completed | Progress: 100%\n\nVideo URL: https://files.evolink.ai/.../cgt-20260227224931-8vl7s.mp4\nDownloading video to my_first_video.mp4...\nSaved: my_first_video.mp4 (2847 KB)\n","text",[27,2186,2183],{"__ignoreMap":140},[10,2188,2189],{},"That's it — about 50 seconds from API call to video file on disk.",[17,2191,2192],{},[10,2193,2194,2197],{},[22,2195,2196],{},"Important:"," Video URLs expire after 24 hours. Always download the file promptly or store it in your own storage (S3, GCS, Cloudflare R2, etc.).",[17,2199,2200],{},[10,2201,2202,2204],{},[22,2203,303],{}," Don't rely on the video URL for long-term storage. Build your pipeline to download immediately after completion. If you're processing videos asynchronously, use webhooks (covered below) to trigger downloads the moment they're ready.",[10,2206,2207,2208,2211],{},"For tips on writing effective prompts, see the ",[36,2209,2210],{"href":1765},"Seedance 2.0 Prompt Guide"," — it covers shot-script format, style keywords, and timing syntax.",[44,2213],{},[47,2215,2217],{"id":2216},"poll-for-results-understanding-the-async-workflow","Poll for Results: Understanding the Async Workflow",[10,2219,2220,2221,2224],{},"Video generation takes 30–120+ seconds depending on duration and quality. The API uses an ",[22,2222,2223],{},"asynchronous task pattern"," — the same pattern used by OpenAI, Stability AI, and most other generative AI APIs:",[69,2226,2227,2237,2247],{},[72,2228,2229,2232,2233,2236],{},[22,2230,2231],{},"Submit"," → POST to ",[27,2234,2235],{},"/v1/videos/generations"," → get a task ID instantly",[72,2238,2239,2242,2243,2246],{},[22,2240,2241],{},"Poll"," → GET ",[27,2244,2245],{},"/v1/tasks/{task_id}"," → check status periodically",[72,2248,2249,2252,2253,2256,2257,2260],{},[22,2250,2251],{},"Retrieve"," → When ",[27,2254,2255],{},"status: \"completed\"",", the ",[27,2258,2259],{},"results"," array contains video URLs",[10,2262,2263],{},"This pattern exists because video generation is computationally expensive. A synchronous HTTP request would time out long before the video is ready.",[91,2265,2267],{"id":2266},"task-status-lifecycle","Task Status Lifecycle",[135,2269,2272],{"className":2270,"code":2271,"language":2184},[2182],"pending → processing → completed\n                    ↘ failed\n",[27,2273,2271],{"__ignoreMap":140},[2035,2275,2276,2289],{},[2038,2277,2278],{},[2041,2279,2280,2283,2286],{},[2044,2281,2282],{},"Status",[2044,2284,2285],{},"What's Happening",[2044,2287,2288],{},"Typical Duration",[2051,2290,2291,2303,2318,2333],{},[2041,2292,2293,2297,2300],{},[2056,2294,2295],{},[27,2296,2075],{},[2056,2298,2299],{},"Task is queued, waiting for GPU resources",[2056,2301,2302],{},"0–30 seconds",[2041,2304,2305,2309,2315],{},[2056,2306,2307],{},[27,2308,2079],{},[2056,2310,2311,2312,2314],{},"Video is being generated — ",[27,2313,823],{}," updates in real-time",[2056,2316,2317],{},"30–120 seconds",[2041,2319,2320,2324,2330],{},[2056,2321,2322],{},[27,2323,2083],{},[2056,2325,2326,2327,2329],{},"Done! ",[27,2328,2259],{}," array has your video URL(s)",[2056,2331,2332],{},"Terminal state",[2041,2334,2335,2339,2342],{},[2056,2336,2337],{},[27,2338,2086],{},[2056,2340,2341],{},"Something went wrong — check the error details",[2056,2343,2332],{},[91,2345,2347],{"id":2346},"polling-best-practices","Polling Best Practices",[10,2349,2350,2353],{},[22,2351,2352],{},"Poll interval:"," 10 seconds is a good default. Polling too fast wastes requests and could trigger rate limits; too slow delays your pipeline. For time-critical applications, you can poll every 5 seconds, but there's no benefit to going faster than that.",[10,2355,2356,2359],{},[22,2357,2358],{},"Timeout:"," Set a reasonable upper limit based on your parameters:",[2035,2361,2362,2375],{},[2038,2363,2364],{},[2041,2365,2366,2369,2372],{},[2044,2367,2368],{},"Configuration",[2044,2370,2371],{},"Expected Time",[2044,2373,2374],{},"Suggested Timeout",[2051,2376,2377,2388,2399,2410],{},[2041,2378,2379,2382,2385],{},[2056,2380,2381],{},"4s, 480p",[2056,2383,2384],{},"20–40 seconds",[2056,2386,2387],{},"120 seconds",[2041,2389,2390,2393,2396],{},[2056,2391,2392],{},"5s, 720p",[2056,2394,2395],{},"30–60 seconds",[2056,2397,2398],{},"180 seconds",[2041,2400,2401,2404,2407],{},[2056,2402,2403],{},"10s, 720p",[2056,2405,2406],{},"60–90 seconds",[2056,2408,2409],{},"300 seconds",[2041,2411,2412,2415,2418],{},[2056,2413,2414],{},"15s, 1080p",[2056,2416,2417],{},"90–180 seconds",[2056,2419,2420],{},"600 seconds",[10,2422,2423,2426,2427,2429,2430,2432],{},[22,2424,2425],{},"Progress tracking:"," The ",[27,2428,823],{}," field (0–100) gives you granular feedback — useful for building progress bars in a UI. Progress updates roughly every 5–7 seconds during the ",[27,2431,2079],{}," phase.",[91,2434,2436],{"id":2435},"cancelling-a-task","Cancelling a Task",[10,2438,2439],{},"If you need to stop a generation in progress (wrong prompt, changed your mind), you can cancel it:",[135,2441,2443],{"className":337,"code":2442,"language":339,"meta":140,"style":140},"def cancel_task(task_id):\n    \"\"\"Cancel a pending or processing task. Credits are refunded.\"\"\"\n    response = requests.post(\n        f\"{BASE_URL}/tasks/{task_id}/cancel\",\n        headers=HEADERS\n    )\n    if response.status_code == 200:\n        print(f\"Task {task_id} cancelled. Credits refunded.\")\n    else:\n        print(f\"Cancel failed: {response.json()}\")\n",[27,2444,2445,2455,2460,2468,2489,2497,2501,2516,2537,2544],{"__ignoreMap":140},[144,2446,2447,2449,2452],{"class":146,"line":147},[144,2448,525],{"class":257},[144,2450,2451],{"class":150}," cancel_task",[144,2453,2454],{"class":261},"(task_id):\n",[144,2456,2457],{"class":146,"line":165},[144,2458,2459],{"class":158},"    \"\"\"Cancel a pending or processing task. Credits are refunded.\"\"\"\n",[144,2461,2462,2464,2466],{"class":146,"line":177},[144,2463,1426],{"class":261},[144,2465,265],{"class":257},[144,2467,1431],{"class":261},[144,2469,2470,2472,2474,2476,2478,2480,2482,2484,2487],{"class":146,"line":186},[144,2471,1436],{"class":257},[144,2473,448],{"class":158},[144,2475,678],{"class":154},[144,2477,681],{"class":158},[144,2479,684],{"class":154},[144,2481,687],{"class":261},[144,2483,690],{"class":154},[144,2485,2486],{"class":158},"/cancel\"",[144,2488,451],{"class":261},[144,2490,2491,2493,2495],{"class":146,"line":372},[144,2492,1454],{"class":700},[144,2494,265],{"class":257},[144,2496,706],{"class":154},[144,2498,2499],{"class":146,"line":378},[144,2500,1482],{"class":261},[144,2502,2503,2506,2509,2511,2514],{"class":146,"line":384},[144,2504,2505],{"class":257},"    if",[144,2507,2508],{"class":261}," response.status_code ",[144,2510,853],{"class":257},[144,2512,2513],{"class":154}," 200",[144,2515,859],{"class":261},[144,2517,2518,2520,2522,2524,2526,2528,2530,2532,2535],{"class":146,"line":408},[144,2519,790],{"class":154},[144,2521,793],{"class":261},[144,2523,439],{"class":257},[144,2525,920],{"class":158},[144,2527,684],{"class":154},[144,2529,687],{"class":261},[144,2531,690],{"class":154},[144,2533,2534],{"class":158}," cancelled. Credits refunded.\"",[144,2536,405],{"class":261},[144,2538,2539,2542],{"class":146,"line":419},[144,2540,2541],{"class":257},"    else",[144,2543,859],{"class":261},[144,2545,2546,2548,2550,2552,2555,2557,2560,2562,2564],{"class":146,"line":430},[144,2547,790],{"class":154},[144,2549,793],{"class":261},[144,2551,439],{"class":257},[144,2553,2554],{"class":158},"\"Cancel failed: ",[144,2556,684],{"class":154},[144,2558,2559],{"class":261},"response.json()",[144,2561,690],{"class":154},[144,2563,448],{"class":158},[144,2565,405],{"class":261},[10,2567,2568,2569,2571,2572,2574,2575,279,2577,2579],{},"Cancellation works when ",[27,2570,2124],{}," is ",[27,2573,1825],{},". Once a task reaches ",[27,2576,2083],{},[27,2578,2086],{},", it can't be cancelled. Reserved credits are refunded automatically on cancellation.",[17,2581,2582],{},[10,2583,2584,2586],{},[22,2585,132],{}," Build a cancellation mechanism into your UI early. Users will inevitably submit wrong prompts, and waiting 2 minutes for a bad video wastes both time and credits.",[10,2588,2175,2589,2591,2592,2596],{},[27,2590,2167],{}," function from our setup code handles the standard polling flow. If you want to skip polling entirely, jump to the ",[36,2593,2595],{"href":2594},"#set-up-webhooks-skip-the-polling","Webhooks section"," below.",[44,2598],{},[47,2600,2602],{"id":2601},"animate-an-image-image-to-video","Animate an Image (Image-to-Video)",[10,2604,2605,2606,2609,2610,2614],{},"Got a product photo, character illustration, or landscape you want to bring to life? Pass it as an ",[27,2607,2608],{},"image_url"," and Seedance will animate it. This is one of the most powerful features for ",[36,2611,2613],{"href":2612},"/blog/seedance-2-ecommerce-product-videos","e-commerce product videos"," — take a static product shot and turn it into an engaging video ad.",[10,2616,2617],{},[2618,2619,2620],"em",{},"Uses the same setup and polling function from the first example above.",[135,2622,2624],{"className":337,"code":2623,"language":339,"meta":140,"style":140},"# ── Image-to-Video ────────────────────────────────────────────\ndef image_to_video():\n    payload = {\n        \"model\": \"seedance-2.0\",\n        \"prompt\": (\n            \"@Image1 as the first frame. The scene slowly comes \"\n            \"to life — leaves rustle gently, soft light shifts \"\n            \"across the frame, and the subject blinks naturally.\"\n        ),\n        \"image_urls\": [\n            \"https://example.com/your-image.jpg\"\n        ],\n        \"duration\": 5,\n        \"quality\": \"720p\",\n        \"aspect_ratio\": \"16:9\"\n    }\n\n    print(\"Submitting image-to-video request...\")\n    response = requests.post(\n        f\"{BASE_URL}/videos/generations\",\n        headers=HEADERS,\n        json=payload\n    )\n    response.raise_for_status()\n    task = response.json()\n\n    print(f\"Task created: {task['id']}\")\n    result = wait_for_video(task[\"id\"])\n\n    video_url = result[\"results\"][0]\n    download_video(video_url, \"animated_image.mp4\")\n\n    return result\n",[27,2625,2626,2631,2640,2648,2658,2664,2669,2674,2679,2683,2691,2696,2701,2711,2721,2730,2734,2738,2749,2757,2769,2779,2788,2792,2797,2805,2809,2833,2845,2849,2865,2874,2878],{"__ignoreMap":140},[144,2627,2628],{"class":146,"line":147},[144,2629,2630],{"class":173},"# ── Image-to-Video ────────────────────────────────────────────\n",[144,2632,2633,2635,2638],{"class":146,"line":165},[144,2634,525],{"class":257},[144,2636,2637],{"class":150}," image_to_video",[144,2639,1288],{"class":261},[144,2641,2642,2644,2646],{"class":146,"line":177},[144,2643,1293],{"class":261},[144,2645,265],{"class":257},[144,2647,427],{"class":261},[144,2649,2650,2652,2654,2656],{"class":146,"line":186},[144,2651,1302],{"class":158},[144,2653,436],{"class":261},[144,2655,1307],{"class":158},[144,2657,451],{"class":261},[144,2659,2660,2662],{"class":146,"line":372},[144,2661,1318],{"class":158},[144,2663,1321],{"class":261},[144,2665,2666],{"class":146,"line":378},[144,2667,2668],{"class":158},"            \"@Image1 as the first frame. The scene slowly comes \"\n",[144,2670,2671],{"class":146,"line":384},[144,2672,2673],{"class":158},"            \"to life — leaves rustle gently, soft light shifts \"\n",[144,2675,2676],{"class":146,"line":408},[144,2677,2678],{"class":158},"            \"across the frame, and the subject blinks naturally.\"\n",[144,2680,2681],{"class":146,"line":419},[144,2682,1341],{"class":261},[144,2684,2685,2688],{"class":146,"line":430},[144,2686,2687],{"class":158},"        \"image_urls\"",[144,2689,2690],{"class":261},": [\n",[144,2692,2693],{"class":146,"line":454},[144,2694,2695],{"class":158},"            \"https://example.com/your-image.jpg\"\n",[144,2697,2698],{"class":146,"line":465},[144,2699,2700],{"class":261},"        ],\n",[144,2702,2703,2705,2707,2709],{"class":146,"line":599},[144,2704,1346],{"class":158},[144,2706,436],{"class":261},[144,2708,1351],{"class":154},[144,2710,451],{"class":261},[144,2712,2713,2715,2717,2719],{"class":146,"line":604},[144,2714,1362],{"class":158},[144,2716,436],{"class":261},[144,2718,1367],{"class":158},[144,2720,451],{"class":261},[144,2722,2723,2725,2727],{"class":146,"line":610},[144,2724,1378],{"class":158},[144,2726,436],{"class":261},[144,2728,2729],{"class":158},"\"16:9\"\n",[144,2731,2732],{"class":146,"line":616},[144,2733,1406],{"class":261},[144,2735,2736],{"class":146,"line":622},[144,2737,375],{"emptyLinePlaceholder":57},[144,2739,2740,2742,2744,2747],{"class":146,"line":627},[144,2741,1101],{"class":154},[144,2743,793],{"class":261},[144,2745,2746],{"class":158},"\"Submitting image-to-video request...\"",[144,2748,405],{"class":261},[144,2750,2751,2753,2755],{"class":146,"line":638},[144,2752,1426],{"class":261},[144,2754,265],{"class":257},[144,2756,1431],{"class":261},[144,2758,2759,2761,2763,2765,2767],{"class":146,"line":653},[144,2760,1436],{"class":257},[144,2762,448],{"class":158},[144,2764,678],{"class":154},[144,2766,1443],{"class":158},[144,2768,451],{"class":261},[144,2770,2771,2773,2775,2777],{"class":146,"line":659},[144,2772,1454],{"class":700},[144,2774,265],{"class":257},[144,2776,422],{"class":154},[144,2778,451],{"class":261},[144,2780,2781,2783,2785],{"class":146,"line":670},[144,2782,1469],{"class":700},[144,2784,265],{"class":257},[144,2786,2787],{"class":261},"payload\n",[144,2789,2790],{"class":146,"line":697},[144,2791,1482],{"class":261},[144,2793,2794],{"class":146,"line":709},[144,2795,2796],{"class":261},"    response.raise_for_status()\n",[144,2798,2799,2801,2803],{"class":146,"line":715},[144,2800,1495],{"class":261},[144,2802,265],{"class":257},[144,2804,735],{"class":261},[144,2806,2807],{"class":146,"line":721},[144,2808,375],{"emptyLinePlaceholder":57},[144,2810,2811,2813,2815,2817,2819,2821,2823,2825,2827,2829,2831],{"class":146,"line":727},[144,2812,1101],{"class":154},[144,2814,793],{"class":261},[144,2816,439],{"class":257},[144,2818,1523],{"class":158},[144,2820,684],{"class":154},[144,2822,1528],{"class":261},[144,2824,1531],{"class":158},[144,2826,1534],{"class":261},[144,2828,690],{"class":154},[144,2830,448],{"class":158},[144,2832,405],{"class":261},[144,2834,2835,2837,2839,2841,2843],{"class":146,"line":738},[144,2836,1617],{"class":261},[144,2838,265],{"class":257},[144,2840,1622],{"class":261},[144,2842,1625],{"class":158},[144,2844,1628],{"class":261},[144,2846,2847],{"class":146,"line":743},[144,2848,375],{"emptyLinePlaceholder":57},[144,2850,2851,2853,2855,2857,2859,2861,2863],{"class":146,"line":749},[144,2852,1642],{"class":261},[144,2854,265],{"class":257},[144,2856,1647],{"class":261},[144,2858,1650],{"class":158},[144,2860,1561],{"class":261},[144,2862,782],{"class":154},[144,2864,763],{"class":261},[144,2866,2867,2869,2872],{"class":146,"line":766},[144,2868,1688],{"class":261},[144,2870,2871],{"class":158},"\"animated_image.mp4\"",[144,2873,405],{"class":261},[144,2875,2876],{"class":146,"line":787},[144,2877,375],{"emptyLinePlaceholder":57},[144,2879,2880,2882],{"class":146,"line":833},[144,2881,1702],{"class":257},[144,2883,1705],{"class":261},[10,2885,2886],{},"Let's unpack what's different from text-to-video:",[96,2888,2889,2901,2921],{},[72,2890,2891,2896,2897,2900],{},[22,2892,2893],{},[27,2894,2895],{},"image_urls"," — An array of publicly accessible image URLs. The API fetches these directly, so they must be reachable from the internet (not ",[27,2898,2899],{},"localhost"," or private network URLs).",[72,2902,2903,2909,2910,2912,2913,399,2915,399,2918,492],{},[22,2904,2905,2908],{},[27,2906,2907],{},"@Image1"," in the prompt"," — This tag tells Seedance which image to reference and how. It corresponds to the first URL in ",[27,2911,2895],{},". If you pass three images, you'd use ",[27,2914,2907],{},[27,2916,2917],{},"@Image2",[27,2919,2920],{},"@Image3",[72,2922,2923,2928,2929,2931,2932,2935],{},[22,2924,2925,2926],{},"No ",[27,2927,1821],{}," — Omitted here, which defaults to ",[27,2930,1825],{},". You can set it to ",[27,2933,2934],{},"false"," for silent animation.",[91,2937,2939],{"id":2938},"how-image-tags-work","How @Image Tags Work",[10,2941,2175,2942,2944,2945,2947,2948,2950,2951,2954,2955,2958,2959,2962,2963,492],{},[27,2943,2907],{}," tag in your prompt tells Seedance how to use the image. It references the first URL in the ",[27,2946,2895],{}," array. You can pass up to 9 images (",[27,2949,2907],{}," through ",[27,2952,2953],{},"@Image9","). For a complete guide on multimodal tags including ",[27,2956,2957],{},"@Video"," and ",[27,2960,2961],{},"@Audio",", see the ",[36,2964,2966],{"href":2965},"/blog/seedance-2-multimodal-tags-guide","Multimodal @Tags Guide",[10,2968,2969],{},"Common patterns:",[2035,2971,2972,2985],{},[2038,2973,2974],{},[2041,2975,2976,2979,2982],{},[2044,2977,2978],{},"Prompt Pattern",[2044,2980,2981],{},"What It Does",[2044,2983,2984],{},"Best For",[2051,2986,2987,3000,3013,3026,3039],{},[2041,2988,2989,2994,2997],{},[2056,2990,2991],{},[27,2992,2993],{},"@Image1 as first frame",[2056,2995,2996],{},"Uses the image as the opening frame",[2056,2998,2999],{},"Product showcases, scene setting",[2041,3001,3002,3007,3010],{},[2056,3003,3004],{},[27,3005,3006],{},"@Image1 as last frame",[2056,3008,3009],{},"Uses the image as the closing frame",[2056,3011,3012],{},"Logo reveals, transitions",[2041,3014,3015,3020,3023],{},[2056,3016,3017],{},[27,3018,3019],{},"@Image1 as character reference",[2056,3021,3022],{},"Maintains the character's appearance",[2056,3024,3025],{},"Consistent characters across clips",[2041,3027,3028,3033,3036],{},[2056,3029,3030],{},[27,3031,3032],{},"@Image1 as style reference",[2056,3034,3035],{},"Applies the image's visual style",[2056,3037,3038],{},"Brand consistency, art direction",[2041,3040,3041,3046,3049],{},[2056,3042,3043],{},[27,3044,3045],{},"@Image1 as first frame, @Image2 as last frame",[2056,3047,3048],{},"Creates a transition between two images",[2056,3050,3051],{},"Before/after, transformations",[10,3053,3054],{},"The actual response from our test:",[135,3056,3058],{"className":1855,"code":3057,"language":1857,"meta":140,"style":140},"{\n  \"created\": 1772204037,\n  \"id\": \"task-unified-1772204036-lify8u5p\",\n  \"model\": \"seedance-2.0\",\n  \"object\": \"video.generation.task\",\n  \"progress\": 0,\n  \"status\": \"pending\",\n  \"task_info\": {\n    \"can_cancel\": true,\n    \"estimated_time\": 145\n  },\n  \"type\": \"video\",\n  \"usage\": {\n    \"billing_rule\": \"per_second\",\n    \"credits_reserved\": 17.784,\n    \"user_group\": \"default\"\n  }\n}\n",[27,3059,3060,3064,3075,3086,3096,3106,3116,3126,3132,3142,3151,3155,3165,3171,3181,3191,3199,3203],{"__ignoreMap":140},[144,3061,3062],{"class":146,"line":147},[144,3063,1864],{"class":261},[144,3065,3066,3068,3070,3073],{"class":146,"line":165},[144,3067,1869],{"class":154},[144,3069,436],{"class":261},[144,3071,3072],{"class":154},"1772204037",[144,3074,451],{"class":261},[144,3076,3077,3079,3081,3084],{"class":146,"line":177},[144,3078,1881],{"class":154},[144,3080,436],{"class":261},[144,3082,3083],{"class":158},"\"task-unified-1772204036-lify8u5p\"",[144,3085,451],{"class":261},[144,3087,3088,3090,3092,3094],{"class":146,"line":186},[144,3089,1893],{"class":154},[144,3091,436],{"class":261},[144,3093,1307],{"class":158},[144,3095,451],{"class":261},[144,3097,3098,3100,3102,3104],{"class":146,"line":372},[144,3099,1904],{"class":154},[144,3101,436],{"class":261},[144,3103,1909],{"class":158},[144,3105,451],{"class":261},[144,3107,3108,3110,3112,3114],{"class":146,"line":378},[144,3109,1916],{"class":154},[144,3111,436],{"class":261},[144,3113,782],{"class":154},[144,3115,451],{"class":261},[144,3117,3118,3120,3122,3124],{"class":146,"line":384},[144,3119,1927],{"class":154},[144,3121,436],{"class":261},[144,3123,1932],{"class":158},[144,3125,451],{"class":261},[144,3127,3128,3130],{"class":146,"line":408},[144,3129,1939],{"class":154},[144,3131,1942],{"class":261},[144,3133,3134,3136,3138,3140],{"class":146,"line":419},[144,3135,1947],{"class":154},[144,3137,436],{"class":261},[144,3139,1825],{"class":154},[144,3141,451],{"class":261},[144,3143,3144,3146,3148],{"class":146,"line":430},[144,3145,1958],{"class":154},[144,3147,436],{"class":261},[144,3149,3150],{"class":154},"145\n",[144,3152,3153],{"class":146,"line":454},[144,3154,1968],{"class":261},[144,3156,3157,3159,3161,3163],{"class":146,"line":465},[144,3158,1973],{"class":154},[144,3160,436],{"class":261},[144,3162,1978],{"class":158},[144,3164,451],{"class":261},[144,3166,3167,3169],{"class":146,"line":599},[144,3168,1985],{"class":154},[144,3170,1942],{"class":261},[144,3172,3173,3175,3177,3179],{"class":146,"line":604},[144,3174,1992],{"class":154},[144,3176,436],{"class":261},[144,3178,1997],{"class":158},[144,3180,451],{"class":261},[144,3182,3183,3185,3187,3189],{"class":146,"line":610},[144,3184,2004],{"class":154},[144,3186,436],{"class":261},[144,3188,2009],{"class":154},[144,3190,451],{"class":261},[144,3192,3193,3195,3197],{"class":146,"line":616},[144,3194,2016],{"class":154},[144,3196,436],{"class":261},[144,3198,2021],{"class":158},[144,3200,3201],{"class":146,"line":622},[144,3202,2026],{"class":261},[144,3204,3205],{"class":146,"line":627},[144,3206,468],{"class":261},[10,3208,3209,3210,3212],{},"Image-to-video follows the exact same async pattern — submit, poll, download. The ",[27,3211,2104],{}," is slightly longer because the model needs to analyze the input image.",[91,3214,3216],{"id":3215},"image-requirements","Image Requirements",[2035,3218,3219,3229],{},[2038,3220,3221],{},[2041,3222,3223,3226],{},[2044,3224,3225],{},"Constraint",[2044,3227,3228],{},"Value",[2051,3230,3231,3239,3247,3255,3263],{},[2041,3232,3233,3236],{},[2056,3234,3235],{},"Max images",[2056,3237,3238],{},"9 per request",[2041,3240,3241,3244],{},[2056,3242,3243],{},"Max file size",[2056,3245,3246],{},"30 MB per image",[2041,3248,3249,3252],{},[2056,3250,3251],{},"Supported formats",[2056,3253,3254],{},"JPEG, PNG, WebP, BMP, TIFF, GIF",[2041,3256,3257,3260],{},[2056,3258,3259],{},"URL requirement",[2056,3261,3262],{},"Must be publicly accessible",[2041,3264,3265,3268],{},[2056,3266,3267],{},"Recommended resolution",[2056,3269,3270],{},"At least 720px on the shorter side",[17,3272,3273],{},[10,3274,3275,3277,3278,3280],{},[22,3276,303],{}," Passing a local file path instead of a URL. The ",[27,3279,2895],{}," field requires publicly accessible HTTP/HTTPS URLs. If your images are local, upload them to S3, Cloudflare R2, or even a temporary file hosting service first.",[17,3282,3283],{},[10,3284,3285,3288],{},[22,3286,3287],{},"Restriction:"," Seedance does not support uploading realistic human face images. The system automatically rejects them. Use illustrated or stylized characters instead.",[91,3290,3292],{"id":3291},"hosting-images-for-the-api","Hosting Images for the API",[10,3294,3295],{},"If you don't have a CDN, here are quick options for getting a public URL:",[135,3297,3299],{"className":337,"code":3298,"language":339,"meta":140,"style":140},"# Option 1: Upload to S3 (if you have AWS)\nimport boto3\ns3 = boto3.client('s3')\ns3.upload_file('local_image.jpg', 'my-bucket', 'seedance/input.jpg')\nimage_url = f\"https://my-bucket.s3.amazonaws.com/seedance/input.jpg\"\n\n# Option 2: Use a temporary file hosting API\n# Many services offer free temporary hosting for testing\n",[27,3300,3301,3306,3313,3328,3348,3361,3365,3370],{"__ignoreMap":140},[144,3302,3303],{"class":146,"line":147},[144,3304,3305],{"class":173},"# Option 1: Upload to S3 (if you have AWS)\n",[144,3307,3308,3310],{"class":146,"line":165},[144,3309,346],{"class":257},[144,3311,3312],{"class":261}," boto3\n",[144,3314,3315,3318,3320,3323,3326],{"class":146,"line":177},[144,3316,3317],{"class":261},"s3 ",[144,3319,265],{"class":257},[144,3321,3322],{"class":261}," boto3.client(",[144,3324,3325],{"class":158},"'s3'",[144,3327,405],{"class":261},[144,3329,3330,3333,3336,3338,3341,3343,3346],{"class":146,"line":186},[144,3331,3332],{"class":261},"s3.upload_file(",[144,3334,3335],{"class":158},"'local_image.jpg'",[144,3337,399],{"class":261},[144,3339,3340],{"class":158},"'my-bucket'",[144,3342,399],{"class":261},[144,3344,3345],{"class":158},"'seedance/input.jpg'",[144,3347,405],{"class":261},[144,3349,3350,3353,3355,3358],{"class":146,"line":372},[144,3351,3352],{"class":261},"image_url ",[144,3354,265],{"class":257},[144,3356,3357],{"class":257}," f",[144,3359,3360],{"class":158},"\"https://my-bucket.s3.amazonaws.com/seedance/input.jpg\"\n",[144,3362,3363],{"class":146,"line":378},[144,3364,375],{"emptyLinePlaceholder":57},[144,3366,3367],{"class":146,"line":384},[144,3368,3369],{"class":173},"# Option 2: Use a temporary file hosting API\n",[144,3371,3372],{"class":146,"line":408},[144,3373,3374],{"class":173},"# Many services offer free temporary hosting for testing\n",[10,3376,3377,3378,492],{},"For advanced image-to-video techniques — first-last frame control, multi-image composition, and e-commerce product animation — see the ",[36,3379,3381],{"href":3380},"/blog/seedance-2-image-to-video-api","Image-to-Video deep dive",[44,3383],{},[47,3385,3387],{"id":3386},"customize-your-videos","Customize Your Videos",[10,3389,3390],{},"Every parameter you can tune in a generation request:",[2035,3392,3393,3412],{},[2038,3394,3395],{},[2041,3396,3397,3400,3403,3406,3409],{},[2044,3398,3399],{},"Parameter",[2044,3401,3402],{},"Type",[2044,3404,3405],{},"Default",[2044,3407,3408],{},"Options",[2044,3410,3411],{},"Description",[2051,3413,3414,3433,3449,3466,3489,3521,3543,3560,3577,3594],{},[2041,3415,3416,3420,3423,3426,3430],{},[2056,3417,3418],{},[27,3419,1746],{},[2056,3421,3422],{},"string",[2056,3424,3425],{},"—",[2056,3427,3428],{},[27,3429,1750],{},[2056,3431,3432],{},"Required. The model to use.",[2041,3434,3435,3439,3441,3443,3446],{},[2056,3436,3437],{},[27,3438,1761],{},[2056,3440,3422],{},[2056,3442,3425],{},[2056,3444,3445],{},"≤2000 tokens",[2056,3447,3448],{},"Required. Video description with optional @tags.",[2041,3450,3451,3455,3458,3460,3463],{},[2056,3452,3453],{},[27,3454,1773],{},[2056,3456,3457],{},"integer",[2056,3459,1351],{},[2056,3461,3462],{},"4–15",[2056,3464,3465],{},"Video length in seconds.",[2041,3467,3468,3472,3474,3478,3486],{},[2056,3469,3470],{},[27,3471,1781],{},[2056,3473,3422],{},[2056,3475,3476],{},[27,3477,1785],{},[2056,3479,3480,399,3482,399,3484],{},[27,3481,1789],{},[27,3483,1785],{},[27,3485,1793],{},[2056,3487,3488],{},"Resolution tier. Higher = more credits.",[2041,3490,3491,3495,3497,3501,3518],{},[2056,3492,3493],{},[27,3494,1801],{},[2056,3496,3422],{},[2056,3498,3499],{},[27,3500,1805],{},[2056,3502,3503,399,3505,399,3507,399,3509,399,3512,399,3515],{},[27,3504,1805],{},[27,3506,1809],{},[27,3508,1813],{},[27,3510,3511],{},"4:3",[27,3513,3514],{},"3:4",[27,3516,3517],{},"21:9",[2056,3519,3520],{},"Output aspect ratio.",[2041,3522,3523,3527,3530,3534,3540],{},[2056,3524,3525],{},[27,3526,1821],{},[2056,3528,3529],{},"boolean",[2056,3531,3532],{},[27,3533,1825],{},[2056,3535,3536,399,3538],{},[27,3537,1825],{},[27,3539,2934],{},[2056,3541,3542],{},"Enable AI-generated audio/music.",[2041,3544,3545,3549,3552,3554,3557],{},[2056,3546,3547],{},[27,3548,2895],{},[2056,3550,3551],{},"array",[2056,3553,3425],{},[2056,3555,3556],{},"≤9 images",[2056,3558,3559],{},"Reference images. Use @Image1, @Image2... in prompt.",[2041,3561,3562,3567,3569,3571,3574],{},[2056,3563,3564],{},[27,3565,3566],{},"video_urls",[2056,3568,3551],{},[2056,3570,3425],{},[2056,3572,3573],{},"≤3 videos",[2056,3575,3576],{},"Reference videos. Use @Video1, @Video2... in prompt.",[2041,3578,3579,3584,3586,3588,3591],{},[2056,3580,3581],{},[27,3582,3583],{},"audio_urls",[2056,3585,3551],{},[2056,3587,3425],{},[2056,3589,3590],{},"≤3 audio files",[2056,3592,3593],{},"Reference audio. Use @Audio1, @Audio2... in prompt.",[2041,3595,3596,3601,3603,3605,3608],{},[2056,3597,3598],{},[27,3599,3600],{},"callback_url",[2056,3602,3422],{},[2056,3604,3425],{},[2056,3606,3607],{},"HTTPS URL",[2056,3609,3610],{},"Webhook for completion notification.",[17,3612,3613],{},[10,3614,3615,3618,3619,2958,3621,3623,3624,399,3626,3628,3629,2950,3631,3633,3634,3637],{},[22,3616,3617],{},"Seedance 2.0 vs 1.5 Note:"," All parameters above work with both ",[27,3620,1750],{},[27,3622,29],{},". The key difference: ",[27,3625,3566],{},[27,3627,3583],{},", and multi-image references (",[27,3630,2917],{},[27,3632,2953],{},") are 2.0-only features. If you use them with 1.5, the API returns a ",[27,3635,3636],{},"400"," error with a clear message indicating the feature isn't supported.",[91,3639,3641],{"id":3640},"quick-examples","Quick Examples",[10,3643,3644],{},[22,3645,3646],{},"Vertical video for social media (TikTok/Reels):",[10,3648,3649],{},[2618,3650,2620],{},[135,3652,3654],{"className":337,"code":3653,"language":339,"meta":140,"style":140},"payload = {\n    \"model\": \"seedance-2.0\",\n    \"prompt\": \"A barista pours latte art in slow motion. Close-up overhead shot.\",\n    \"duration\": 8,\n    \"quality\": \"1080p\",\n    \"aspect_ratio\": \"9:16\",       # Vertical for mobile\n    \"generate_audio\": True\n}\n",[27,3655,3656,3665,3676,3688,3700,3712,3728,3738],{"__ignoreMap":140},[144,3657,3658,3661,3663],{"class":146,"line":147},[144,3659,3660],{"class":261},"payload ",[144,3662,265],{"class":257},[144,3664,427],{"class":261},[144,3666,3667,3670,3672,3674],{"class":146,"line":165},[144,3668,3669],{"class":158},"    \"model\"",[144,3671,436],{"class":261},[144,3673,1307],{"class":158},[144,3675,451],{"class":261},[144,3677,3678,3681,3683,3686],{"class":146,"line":177},[144,3679,3680],{"class":158},"    \"prompt\"",[144,3682,436],{"class":261},[144,3684,3685],{"class":158},"\"A barista pours latte art in slow motion. Close-up overhead shot.\"",[144,3687,451],{"class":261},[144,3689,3690,3693,3695,3698],{"class":146,"line":186},[144,3691,3692],{"class":158},"    \"duration\"",[144,3694,436],{"class":261},[144,3696,3697],{"class":154},"8",[144,3699,451],{"class":261},[144,3701,3702,3705,3707,3710],{"class":146,"line":372},[144,3703,3704],{"class":158},"    \"quality\"",[144,3706,436],{"class":261},[144,3708,3709],{"class":158},"\"1080p\"",[144,3711,451],{"class":261},[144,3713,3714,3717,3719,3722,3725],{"class":146,"line":378},[144,3715,3716],{"class":158},"    \"aspect_ratio\"",[144,3718,436],{"class":261},[144,3720,3721],{"class":158},"\"9:16\"",[144,3723,3724],{"class":261},",       ",[144,3726,3727],{"class":173},"# Vertical for mobile\n",[144,3729,3730,3733,3735],{"class":146,"line":384},[144,3731,3732],{"class":158},"    \"generate_audio\"",[144,3734,436],{"class":261},[144,3736,3737],{"class":154},"True\n",[144,3739,3740],{"class":146,"line":408},[144,3741,468],{"class":261},[10,3743,2175,3744,3746,3747,3749],{},[27,3745,1809],{}," aspect ratio generates a 1080×1920 video — native resolution for TikTok, Instagram Reels, and YouTube Shorts. The ",[27,3748,1793],{}," quality tier ensures crisp visuals on mobile screens.",[10,3751,3752],{},[22,3753,3754],{},"Cinematic widescreen with camera movement:",[135,3756,3758],{"className":337,"code":3757,"language":339,"meta":140,"style":140},"payload = {\n    \"model\": \"seedance-2.0\",\n    \"prompt\": (\n        \"Aerial drone shot over a misty mountain range at sunrise. \"\n        \"Camera slowly pushes forward, revealing a hidden valley. \"\n        \"Cinematic color grading, volumetric lighting.\"\n    ),\n    \"duration\": 10,\n    \"quality\": \"1080p\",\n    \"aspect_ratio\": \"21:9\",       # Ultra-widescreen cinematic\n    \"generate_audio\": True\n}\n",[27,3759,3760,3768,3778,3784,3789,3794,3799,3804,3814,3824,3838,3846],{"__ignoreMap":140},[144,3761,3762,3764,3766],{"class":146,"line":147},[144,3763,3660],{"class":261},[144,3765,265],{"class":257},[144,3767,427],{"class":261},[144,3769,3770,3772,3774,3776],{"class":146,"line":165},[144,3771,3669],{"class":158},[144,3773,436],{"class":261},[144,3775,1307],{"class":158},[144,3777,451],{"class":261},[144,3779,3780,3782],{"class":146,"line":177},[144,3781,3680],{"class":158},[144,3783,1321],{"class":261},[144,3785,3786],{"class":146,"line":186},[144,3787,3788],{"class":158},"        \"Aerial drone shot over a misty mountain range at sunrise. \"\n",[144,3790,3791],{"class":146,"line":372},[144,3792,3793],{"class":158},"        \"Camera slowly pushes forward, revealing a hidden valley. \"\n",[144,3795,3796],{"class":146,"line":378},[144,3797,3798],{"class":158},"        \"Cinematic color grading, volumetric lighting.\"\n",[144,3800,3801],{"class":146,"line":384},[144,3802,3803],{"class":261},"    ),\n",[144,3805,3806,3808,3810,3812],{"class":146,"line":408},[144,3807,3692],{"class":158},[144,3809,436],{"class":261},[144,3811,536],{"class":154},[144,3813,451],{"class":261},[144,3815,3816,3818,3820,3822],{"class":146,"line":419},[144,3817,3704],{"class":158},[144,3819,436],{"class":261},[144,3821,3709],{"class":158},[144,3823,451],{"class":261},[144,3825,3826,3828,3830,3833,3835],{"class":146,"line":430},[144,3827,3716],{"class":158},[144,3829,436],{"class":261},[144,3831,3832],{"class":158},"\"21:9\"",[144,3834,3724],{"class":261},[144,3836,3837],{"class":173},"# Ultra-widescreen cinematic\n",[144,3839,3840,3842,3844],{"class":146,"line":454},[144,3841,3732],{"class":158},[144,3843,436],{"class":261},[144,3845,3737],{"class":154},[144,3847,3848],{"class":146,"line":465},[144,3849,468],{"class":261},[10,3851,3852,3853,492],{},"For programmatic camera control — dolly zooms, orbital shots, and Hitchcock-style movements — see the ",[36,3854,3856],{"href":3855},"/blog/seedance-2-camera-movement-api","Camera Movement API Guide",[10,3858,3859],{},[22,3860,3861],{},"Silent video for a website background:",[135,3863,3865],{"className":337,"code":3864,"language":339,"meta":140,"style":140},"payload = {\n    \"model\": \"seedance-2.0\",\n    \"prompt\": \"Abstract flowing particles in deep blue and gold. Slow, meditative movement.\",\n    \"duration\": 15,               # Max duration for seamless loops\n    \"quality\": \"720p\",\n    \"aspect_ratio\": \"21:9\",       # Wide background\n    \"generate_audio\": False       # No audio for autoplay backgrounds\n}\n",[27,3866,3867,3875,3885,3896,3911,3921,3934,3946],{"__ignoreMap":140},[144,3868,3869,3871,3873],{"class":146,"line":147},[144,3870,3660],{"class":261},[144,3872,265],{"class":257},[144,3874,427],{"class":261},[144,3876,3877,3879,3881,3883],{"class":146,"line":165},[144,3878,3669],{"class":158},[144,3880,436],{"class":261},[144,3882,1307],{"class":158},[144,3884,451],{"class":261},[144,3886,3887,3889,3891,3894],{"class":146,"line":177},[144,3888,3680],{"class":158},[144,3890,436],{"class":261},[144,3892,3893],{"class":158},"\"Abstract flowing particles in deep blue and gold. Slow, meditative movement.\"",[144,3895,451],{"class":261},[144,3897,3898,3900,3902,3905,3908],{"class":146,"line":186},[144,3899,3692],{"class":158},[144,3901,436],{"class":261},[144,3903,3904],{"class":154},"15",[144,3906,3907],{"class":261},",               ",[144,3909,3910],{"class":173},"# Max duration for seamless loops\n",[144,3912,3913,3915,3917,3919],{"class":146,"line":372},[144,3914,3704],{"class":158},[144,3916,436],{"class":261},[144,3918,1367],{"class":158},[144,3920,451],{"class":261},[144,3922,3923,3925,3927,3929,3931],{"class":146,"line":378},[144,3924,3716],{"class":158},[144,3926,436],{"class":261},[144,3928,3832],{"class":158},[144,3930,3724],{"class":261},[144,3932,3933],{"class":173},"# Wide background\n",[144,3935,3936,3938,3940,3943],{"class":146,"line":384},[144,3937,3732],{"class":158},[144,3939,436],{"class":261},[144,3941,3942],{"class":154},"False",[144,3944,3945],{"class":173},"       # No audio for autoplay backgrounds\n",[144,3947,3948],{"class":146,"line":408},[144,3949,468],{"class":261},[10,3951,3952],{},[22,3953,3954],{},"Budget-friendly draft (fast iteration):",[135,3956,3958],{"className":337,"code":3957,"language":339,"meta":140,"style":140},"payload = {\n    \"model\": \"seedance-2.0\",\n    \"prompt\": \"A cat wearing sunglasses sits at a DJ booth. Neon club lighting.\",\n    \"duration\": 4,                # Minimum duration = fastest generation\n    \"quality\": \"480p\",            # Lowest quality = cheapest credits\n    \"aspect_ratio\": \"16:9\"\n}\n",[27,3959,3960,3968,3978,3989,4004,4018,4026],{"__ignoreMap":140},[144,3961,3962,3964,3966],{"class":146,"line":147},[144,3963,3660],{"class":261},[144,3965,265],{"class":257},[144,3967,427],{"class":261},[144,3969,3970,3972,3974,3976],{"class":146,"line":165},[144,3971,3669],{"class":158},[144,3973,436],{"class":261},[144,3975,1307],{"class":158},[144,3977,451],{"class":261},[144,3979,3980,3982,3984,3987],{"class":146,"line":177},[144,3981,3680],{"class":158},[144,3983,436],{"class":261},[144,3985,3986],{"class":158},"\"A cat wearing sunglasses sits at a DJ booth. Neon club lighting.\"",[144,3988,451],{"class":261},[144,3990,3991,3993,3995,3998,4001],{"class":146,"line":186},[144,3992,3692],{"class":158},[144,3994,436],{"class":261},[144,3996,3997],{"class":154},"4",[144,3999,4000],{"class":261},",                ",[144,4002,4003],{"class":173},"# Minimum duration = fastest generation\n",[144,4005,4006,4008,4010,4013,4015],{"class":146,"line":372},[144,4007,3704],{"class":158},[144,4009,436],{"class":261},[144,4011,4012],{"class":158},"\"480p\"",[144,4014,1386],{"class":261},[144,4016,4017],{"class":173},"# Lowest quality = cheapest credits\n",[144,4019,4020,4022,4024],{"class":146,"line":378},[144,4021,3716],{"class":158},[144,4023,436],{"class":261},[144,4025,2729],{"class":158},[144,4027,4028],{"class":146,"line":384},[144,4029,468],{"class":261},[17,4031,4032],{},[10,4033,4034,4036,4037,2958,4040,4043,4044,4046],{},[22,4035,132],{}," During development, always use ",[27,4038,4039],{},"duration: 4",[27,4041,4042],{},"quality: \"480p\"",". This is the cheapest and fastest combination — ideal for iterating on prompts. Once you're happy with the content, render the final version at ",[27,4045,1793],{}," with your desired duration.",[91,4048,4050],{"id":4049},"credit-cost-estimation","Credit Cost Estimation",[10,4052,4053],{},"Credits scale with duration and quality. Here's a rough guide:",[2035,4055,4056,4075],{},[2038,4057,4058],{},[2041,4059,4060,4063,4066,4069,4072],{},[2044,4061,4062],{},"Quality",[2044,4064,4065],{},"4s",[2044,4067,4068],{},"5s",[2044,4070,4071],{},"10s",[2044,4073,4074],{},"15s",[2051,4076,4077,4093,4109],{},[2041,4078,4079,4081,4084,4087,4090],{},[2056,4080,1789],{},[2056,4082,4083],{},"~8",[2056,4085,4086],{},"~10",[2056,4088,4089],{},"~20",[2056,4091,4092],{},"~30",[2041,4094,4095,4097,4100,4103,4106],{},[2056,4096,1785],{},[2056,4098,4099],{},"~14",[2056,4101,4102],{},"~18",[2056,4104,4105],{},"~36",[2056,4107,4108],{},"~53",[2041,4110,4111,4113,4116,4119,4122],{},[2056,4112,1793],{},[2056,4114,4115],{},"~22",[2056,4117,4118],{},"~28",[2056,4120,4121],{},"~55",[2056,4123,4124],{},"~83",[10,4126,4127],{},[2618,4128,4129,4130,4132,4133,4137],{},"Approximate credits. Actual costs shown in ",[27,4131,2114],{}," field. Check the ",[36,4134,4136],{"href":210,"rel":4135},[40],"EvoLink dashboard"," for current rates.",[10,4139,4140,4141,399,4144,399,4146,4148,4149,4152,4153,492],{},"The multimodal reference system — ",[27,4142,4143],{},"@Image",[27,4145,2957],{},[27,4147,2961],{}," tags — is where Seedance 2.0 truly shines. You can replicate ",[36,4150,4151],{"href":3855},"camera movements"," from reference videos, maintain character consistency across shots, and sync to audio beats. For a complete guide, read ",[36,4154,4155],{"href":2965},"The Ultimate Guide to @Tags",[44,4157],{},[47,4159,4161],{"id":4160},"handle-errors-gracefully","Handle Errors Gracefully",[10,4163,4164],{},"API calls fail. Networks drop. Rate limits hit. Here's how to build resilient code that handles every real error scenario.",[91,4166,4168],{"id":4167},"common-error-responses","Common Error Responses",[10,4170,4171],{},"Every error follows the same format:",[135,4173,4175],{"className":1855,"code":4174,"language":1857,"meta":140,"style":140},"{\n  \"error\": {\n    \"message\": \"description of what went wrong\",\n    \"type\": \"error_category\",\n    \"code\": \"specific_error_code\"\n  }\n}\n",[27,4176,4177,4181,4188,4200,4212,4222,4226],{"__ignoreMap":140},[144,4178,4179],{"class":146,"line":147},[144,4180,1864],{"class":261},[144,4182,4183,4186],{"class":146,"line":165},[144,4184,4185],{"class":154},"  \"error\"",[144,4187,1942],{"class":261},[144,4189,4190,4193,4195,4198],{"class":146,"line":177},[144,4191,4192],{"class":154},"    \"message\"",[144,4194,436],{"class":261},[144,4196,4197],{"class":158},"\"description of what went wrong\"",[144,4199,451],{"class":261},[144,4201,4202,4205,4207,4210],{"class":146,"line":186},[144,4203,4204],{"class":154},"    \"type\"",[144,4206,436],{"class":261},[144,4208,4209],{"class":158},"\"error_category\"",[144,4211,451],{"class":261},[144,4213,4214,4217,4219],{"class":146,"line":372},[144,4215,4216],{"class":154},"    \"code\"",[144,4218,436],{"class":261},[144,4220,4221],{"class":158},"\"specific_error_code\"\n",[144,4223,4224],{"class":146,"line":378},[144,4225,2026],{"class":261},[144,4227,4228],{"class":146,"line":384},[144,4229,468],{"class":261},[10,4231,2175,4232,4235,4236,2958,4239,4242,4243,4245,4246,4248,4249,4251],{},[27,4233,4234],{},"error"," object always contains ",[27,4237,4238],{},"message",[27,4240,4241],{},"type",". The ",[27,4244,27],{}," field is present for most errors but not all. Always check ",[27,4247,4241],{}," first, then ",[27,4250,27],{}," for specifics.",[10,4253,4254],{},"Here are real error responses from the API:",[10,4256,4257],{},[22,4258,4259],{},"401 — Invalid API Key:",[135,4261,4263],{"className":1855,"code":4262,"language":1857,"meta":140,"style":140},"{\n  \"error\": {\n    \"message\": \"Invalid token (request id: 20260227225245660301729AApJNAhJ)\",\n    \"type\": \"evo_api_error\"\n  }\n}\n",[27,4264,4265,4269,4275,4286,4295,4299],{"__ignoreMap":140},[144,4266,4267],{"class":146,"line":147},[144,4268,1864],{"class":261},[144,4270,4271,4273],{"class":146,"line":165},[144,4272,4185],{"class":154},[144,4274,1942],{"class":261},[144,4276,4277,4279,4281,4284],{"class":146,"line":177},[144,4278,4192],{"class":154},[144,4280,436],{"class":261},[144,4282,4283],{"class":158},"\"Invalid token (request id: 20260227225245660301729AApJNAhJ)\"",[144,4285,451],{"class":261},[144,4287,4288,4290,4292],{"class":146,"line":186},[144,4289,4204],{"class":154},[144,4291,436],{"class":261},[144,4293,4294],{"class":158},"\"evo_api_error\"\n",[144,4296,4297],{"class":146,"line":372},[144,4298,2026],{"class":261},[144,4300,4301],{"class":146,"line":378},[144,4302,468],{"class":261},[10,4304,4305,4306,4308],{},"This means your API key is wrong, expired, or was revoked. Double-check the ",[27,4307,274],{}," environment variable. A common cause: copying the key with trailing whitespace.",[10,4310,4311],{},[22,4312,4313],{},"400 — Missing Required Field:",[135,4315,4317],{"className":1855,"code":4316,"language":1857,"meta":140,"style":140},"{\n  \"error\": {\n    \"code\": \"invalid_parameter\",\n    \"message\": \"prompt cannot be empty\",\n    \"type\": \"invalid_request_error\"\n  }\n}\n",[27,4318,4319,4323,4329,4340,4351,4360,4364],{"__ignoreMap":140},[144,4320,4321],{"class":146,"line":147},[144,4322,1864],{"class":261},[144,4324,4325,4327],{"class":146,"line":165},[144,4326,4185],{"class":154},[144,4328,1942],{"class":261},[144,4330,4331,4333,4335,4338],{"class":146,"line":177},[144,4332,4216],{"class":154},[144,4334,436],{"class":261},[144,4336,4337],{"class":158},"\"invalid_parameter\"",[144,4339,451],{"class":261},[144,4341,4342,4344,4346,4349],{"class":146,"line":186},[144,4343,4192],{"class":154},[144,4345,436],{"class":261},[144,4347,4348],{"class":158},"\"prompt cannot be empty\"",[144,4350,451],{"class":261},[144,4352,4353,4355,4357],{"class":146,"line":372},[144,4354,4204],{"class":154},[144,4356,436],{"class":261},[144,4358,4359],{"class":158},"\"invalid_request_error\"\n",[144,4361,4362],{"class":146,"line":378},[144,4363,2026],{"class":261},[144,4365,4366],{"class":146,"line":384},[144,4367,468],{"class":261},[10,4369,2175,4370,4372],{},[27,4371,1761],{}," field is required for all generation requests. This also triggers if you pass an empty string or whitespace-only prompt.",[10,4374,4375],{},[22,4376,4377],{},"400 — Invalid Parameter Value:",[135,4379,4381],{"className":1855,"code":4380,"language":1857,"meta":140,"style":140},"{\n  \"error\": {\n    \"code\": \"invalid_parameter\",\n    \"message\": \"duration must be between 4 and 15\",\n    \"type\": \"invalid_request_error\"\n  }\n}\n",[27,4382,4383,4387,4393,4403,4414,4422,4426],{"__ignoreMap":140},[144,4384,4385],{"class":146,"line":147},[144,4386,1864],{"class":261},[144,4388,4389,4391],{"class":146,"line":165},[144,4390,4185],{"class":154},[144,4392,1942],{"class":261},[144,4394,4395,4397,4399,4401],{"class":146,"line":177},[144,4396,4216],{"class":154},[144,4398,436],{"class":261},[144,4400,4337],{"class":158},[144,4402,451],{"class":261},[144,4404,4405,4407,4409,4412],{"class":146,"line":186},[144,4406,4192],{"class":154},[144,4408,436],{"class":261},[144,4410,4411],{"class":158},"\"duration must be between 4 and 15\"",[144,4413,451],{"class":261},[144,4415,4416,4418,4420],{"class":146,"line":372},[144,4417,4204],{"class":154},[144,4419,436],{"class":261},[144,4421,4359],{"class":158},[144,4423,4424],{"class":146,"line":378},[144,4425,2026],{"class":261},[144,4427,4428],{"class":146,"line":384},[144,4429,468],{"class":261},[10,4431,4432,4433,279,4436,4439],{},"Happens when you pass ",[27,4434,4435],{},"duration: 3",[27,4437,4438],{},"duration: 20",". The valid range is 4–15 seconds inclusive.",[10,4441,4442],{},[22,4443,4444],{},"400 — Unsupported Quality Tier:",[135,4446,4448],{"className":1855,"code":4447,"language":1857,"meta":140,"style":140},"{\n  \"error\": {\n    \"code\": \"invalid_parameter\",\n    \"message\": \"quality must be one of: 480p, 720p, 1080p\",\n    \"type\": \"invalid_request_error\"\n  }\n}\n",[27,4449,4450,4454,4460,4470,4481,4489,4493],{"__ignoreMap":140},[144,4451,4452],{"class":146,"line":147},[144,4453,1864],{"class":261},[144,4455,4456,4458],{"class":146,"line":165},[144,4457,4185],{"class":154},[144,4459,1942],{"class":261},[144,4461,4462,4464,4466,4468],{"class":146,"line":177},[144,4463,4216],{"class":154},[144,4465,436],{"class":261},[144,4467,4337],{"class":158},[144,4469,451],{"class":261},[144,4471,4472,4474,4476,4479],{"class":146,"line":186},[144,4473,4192],{"class":154},[144,4475,436],{"class":261},[144,4477,4478],{"class":158},"\"quality must be one of: 480p, 720p, 1080p\"",[144,4480,451],{"class":261},[144,4482,4483,4485,4487],{"class":146,"line":372},[144,4484,4204],{"class":154},[144,4486,436],{"class":261},[144,4488,4359],{"class":158},[144,4490,4491],{"class":146,"line":378},[144,4492,2026],{"class":261},[144,4494,4495],{"class":146,"line":384},[144,4496,468],{"class":261},[10,4498,4499,4500,279,4503,4506,4507,399,4509,4511,4512,492],{},"Common when passing ",[27,4501,4502],{},"\"quality\": \"4k\"",[27,4504,4505],{},"\"quality\": \"hd\"",". Use the exact strings: ",[27,4508,1789],{},[27,4510,1785],{},", or ",[27,4513,1793],{},[10,4515,4516],{},[22,4517,4518],{},"402 — Insufficient Credits:",[135,4520,4522],{"className":1855,"code":4521,"language":1857,"meta":140,"style":140},"{\n  \"error\": {\n    \"message\": \"Insufficient credits. Required: 17.784, Available: 2.100\",\n    \"type\": \"insufficient_quota_error\"\n  }\n}\n",[27,4523,4524,4528,4534,4545,4554,4558],{"__ignoreMap":140},[144,4525,4526],{"class":146,"line":147},[144,4527,1864],{"class":261},[144,4529,4530,4532],{"class":146,"line":165},[144,4531,4185],{"class":154},[144,4533,1942],{"class":261},[144,4535,4536,4538,4540,4543],{"class":146,"line":177},[144,4537,4192],{"class":154},[144,4539,436],{"class":261},[144,4541,4542],{"class":158},"\"Insufficient credits. Required: 17.784, Available: 2.100\"",[144,4544,451],{"class":261},[144,4546,4547,4549,4551],{"class":146,"line":186},[144,4548,4204],{"class":154},[144,4550,436],{"class":261},[144,4552,4553],{"class":158},"\"insufficient_quota_error\"\n",[144,4555,4556],{"class":146,"line":372},[144,4557,2026],{"class":261},[144,4559,4560],{"class":146,"line":378},[144,4561,468],{"class":261},[10,4563,4564,4565,492],{},"Your account doesn't have enough credits. The message tells you exactly how many you need vs. how many you have. Top up at the ",[36,4566,4136],{"href":210,"rel":4567},[40],[10,4569,4570],{},[22,4571,4572],{},"404 — Task Not Found:",[135,4574,4576],{"className":1855,"code":4575,"language":1857,"meta":140,"style":140},"{\n  \"error\": {\n    \"message\": \"Task not found\",\n    \"type\": \"invalid_request_error\",\n    \"code\": \"task_not_found\"\n  }\n}\n",[27,4577,4578,4582,4588,4599,4610,4619,4623],{"__ignoreMap":140},[144,4579,4580],{"class":146,"line":147},[144,4581,1864],{"class":261},[144,4583,4584,4586],{"class":146,"line":165},[144,4585,4185],{"class":154},[144,4587,1942],{"class":261},[144,4589,4590,4592,4594,4597],{"class":146,"line":177},[144,4591,4192],{"class":154},[144,4593,436],{"class":261},[144,4595,4596],{"class":158},"\"Task not found\"",[144,4598,451],{"class":261},[144,4600,4601,4603,4605,4608],{"class":146,"line":186},[144,4602,4204],{"class":154},[144,4604,436],{"class":261},[144,4606,4607],{"class":158},"\"invalid_request_error\"",[144,4609,451],{"class":261},[144,4611,4612,4614,4616],{"class":146,"line":372},[144,4613,4216],{"class":154},[144,4615,436],{"class":261},[144,4617,4618],{"class":158},"\"task_not_found\"\n",[144,4620,4621],{"class":146,"line":378},[144,4622,2026],{"class":261},[144,4624,4625],{"class":146,"line":384},[144,4626,468],{"class":261},[10,4628,4629,4630,4632],{},"Usually means the task ID is wrong, or the task was created more than 24 hours ago (tasks expire). Double-check you're using the ",[27,4631,2060],{}," field from the creation response, not some other field.",[10,4634,4635],{},[22,4636,4637],{},"413 — Image Too Large:",[135,4639,4641],{"className":1855,"code":4640,"language":1857,"meta":140,"style":140},"{\n  \"error\": {\n    \"message\": \"Image file size exceeds 30MB limit\",\n    \"type\": \"request_too_large_error\"\n  }\n}\n",[27,4642,4643,4647,4653,4664,4673,4677],{"__ignoreMap":140},[144,4644,4645],{"class":146,"line":147},[144,4646,1864],{"class":261},[144,4648,4649,4651],{"class":146,"line":165},[144,4650,4185],{"class":154},[144,4652,1942],{"class":261},[144,4654,4655,4657,4659,4662],{"class":146,"line":177},[144,4656,4192],{"class":154},[144,4658,436],{"class":261},[144,4660,4661],{"class":158},"\"Image file size exceeds 30MB limit\"",[144,4663,451],{"class":261},[144,4665,4666,4668,4670],{"class":146,"line":186},[144,4667,4204],{"class":154},[144,4669,436],{"class":261},[144,4671,4672],{"class":158},"\"request_too_large_error\"\n",[144,4674,4675],{"class":146,"line":372},[144,4676,2026],{"class":261},[144,4678,4679],{"class":146,"line":378},[144,4680,468],{"class":261},[10,4682,4683],{},"Compress your image before uploading. For the API, visual quality above 2–3 MB rarely improves results.",[10,4685,4686],{},[22,4687,4688],{},"429 — Rate Limited:",[135,4690,4692],{"className":1855,"code":4691,"language":1857,"meta":140,"style":140},"{\n  \"error\": {\n    \"message\": \"Rate limit exceeded. Please retry after 60 seconds.\",\n    \"type\": \"rate_limit_error\"\n  }\n}\n",[27,4693,4694,4698,4704,4715,4724,4728],{"__ignoreMap":140},[144,4695,4696],{"class":146,"line":147},[144,4697,1864],{"class":261},[144,4699,4700,4702],{"class":146,"line":165},[144,4701,4185],{"class":154},[144,4703,1942],{"class":261},[144,4705,4706,4708,4710,4713],{"class":146,"line":177},[144,4707,4192],{"class":154},[144,4709,436],{"class":261},[144,4711,4712],{"class":158},"\"Rate limit exceeded. Please retry after 60 seconds.\"",[144,4714,451],{"class":261},[144,4716,4717,4719,4721],{"class":146,"line":186},[144,4718,4204],{"class":154},[144,4720,436],{"class":261},[144,4722,4723],{"class":158},"\"rate_limit_error\"\n",[144,4725,4726],{"class":146,"line":372},[144,4727,2026],{"class":261},[144,4729,4730],{"class":146,"line":378},[144,4731,468],{"class":261},[10,4733,4734],{},"You're sending too many requests. The default limit is generous for development, but batch scripts can hit it. Implement exponential backoff (see below).",[10,4736,4737],{},[22,4738,4739],{},"422 — Content Moderation Rejection:",[135,4741,4743],{"className":1855,"code":4742,"language":1857,"meta":140,"style":140},"{\n  \"error\": {\n    \"message\": \"Content rejected by safety filter\",\n    \"type\": \"content_policy_violation\",\n    \"code\": \"content_filtered\"\n  }\n}\n",[27,4744,4745,4749,4755,4766,4777,4786,4790],{"__ignoreMap":140},[144,4746,4747],{"class":146,"line":147},[144,4748,1864],{"class":261},[144,4750,4751,4753],{"class":146,"line":165},[144,4752,4185],{"class":154},[144,4754,1942],{"class":261},[144,4756,4757,4759,4761,4764],{"class":146,"line":177},[144,4758,4192],{"class":154},[144,4760,436],{"class":261},[144,4762,4763],{"class":158},"\"Content rejected by safety filter\"",[144,4765,451],{"class":261},[144,4767,4768,4770,4772,4775],{"class":146,"line":186},[144,4769,4204],{"class":154},[144,4771,436],{"class":261},[144,4773,4774],{"class":158},"\"content_policy_violation\"",[144,4776,451],{"class":261},[144,4778,4779,4781,4783],{"class":146,"line":372},[144,4780,4216],{"class":154},[144,4782,436],{"class":261},[144,4784,4785],{"class":158},"\"content_filtered\"\n",[144,4787,4788],{"class":146,"line":378},[144,4789,2026],{"class":261},[144,4791,4792],{"class":146,"line":384},[144,4793,468],{"class":261},[10,4795,4796,4797,4799],{},"Your prompt or input images triggered the content moderation system. Rephrase your prompt to avoid restricted content. Realistic human faces in ",[27,4798,2895],{}," are automatically rejected.",[91,4801,4803],{"id":4802},"error-reference-table","Error Reference Table",[2035,4805,4806,4823],{},[2038,4807,4808],{},[2041,4809,4810,4813,4815,4817,4820],{},[2044,4811,4812],{},"HTTP Code",[2044,4814,3402],{},[2044,4816,2049],{},[2044,4818,4819],{},"Retryable?",[2044,4821,4822],{},"Action",[2051,4824,4825,4843,4861,4879,4897,4915,4933,4954,4974,4994],{},[2041,4826,4827,4829,4834,4837,4840],{},[2056,4828,3636],{},[2056,4830,4831],{},[27,4832,4833],{},"invalid_request_error",[2056,4835,4836],{},"Bad parameters",[2056,4838,4839],{},"No",[2056,4841,4842],{},"Fix your payload",[2041,4844,4845,4848,4853,4856,4858],{},[2056,4846,4847],{},"401",[2056,4849,4850],{},[27,4851,4852],{},"authentication_error",[2056,4854,4855],{},"Invalid API key",[2056,4857,4839],{},[2056,4859,4860],{},"Verify your key",[2041,4862,4863,4866,4871,4874,4876],{},[2056,4864,4865],{},"402",[2056,4867,4868],{},[27,4869,4870],{},"insufficient_quota_error",[2056,4872,4873],{},"Out of credits",[2056,4875,4839],{},[2056,4877,4878],{},"Top up your account",[2041,4880,4881,4884,4889,4892,4894],{},[2056,4882,4883],{},"404",[2056,4885,4886],{},[27,4887,4888],{},"not_found_error",[2056,4890,4891],{},"Task or model not found",[2056,4893,4839],{},[2056,4895,4896],{},"Check task_id / model name",[2041,4898,4899,4902,4907,4910,4912],{},[2056,4900,4901],{},"413",[2056,4903,4904],{},[27,4905,4906],{},"request_too_large_error",[2056,4908,4909],{},"Payload too big",[2056,4911,4839],{},[2056,4913,4914],{},"Reduce file sizes",[2041,4916,4917,4920,4925,4928,4930],{},[2056,4918,4919],{},"422",[2056,4921,4922],{},[27,4923,4924],{},"content_policy_violation",[2056,4926,4927],{},"Content filtered",[2056,4929,4839],{},[2056,4931,4932],{},"Rephrase prompt",[2041,4934,4935,4938,4943,4946,4951],{},[2056,4936,4937],{},"429",[2056,4939,4940],{},[27,4941,4942],{},"rate_limit_error",[2056,4944,4945],{},"Too many requests",[2056,4947,4948],{},[22,4949,4950],{},"Yes",[2056,4952,4953],{},"Wait 60s, retry",[2041,4955,4956,4959,4964,4967,4971],{},[2056,4957,4958],{},"500",[2056,4960,4961],{},[27,4962,4963],{},"internal_server_error",[2056,4965,4966],{},"Server issue",[2056,4968,4969],{},[22,4970,4950],{},[2056,4972,4973],{},"Retry after a few seconds",[2041,4975,4976,4979,4984,4987,4991],{},[2056,4977,4978],{},"502",[2056,4980,4981],{},[27,4982,4983],{},"bad_gateway",[2056,4985,4986],{},"Upstream error",[2056,4988,4989],{},[22,4990,4950],{},[2056,4992,4993],{},"Retry after 5s",[2041,4995,4996,4999,5004,5007,5011],{},[2056,4997,4998],{},"503",[2056,5000,5001],{},[27,5002,5003],{},"service_unavailable_error",[2056,5005,5006],{},"Service down",[2056,5008,5009],{},[22,5010,4950],{},[2056,5012,5013],{},"Retry after 30s",[91,5015,5017],{"id":5016},"production-ready-error-handling","Production-Ready Error Handling",[10,5019,5020],{},"Wrap your API calls with retry logic for transient errors:",[10,5022,5023],{},[2618,5024,2620],{},[135,5026,5028],{"className":337,"code":5027,"language":339,"meta":140,"style":140},"import random\n\ndef generate_video_with_retry(payload, max_retries=3):\n    \"\"\"\n    Submit a video generation request with automatic retry\n    for transient errors (429, 500, 502, 503).\n    \n    Uses exponential backoff with jitter to avoid thundering herd:\n    - Attempt 1: wait ~1s\n    - Attempt 2: wait ~2s  \n    - Attempt 3: wait ~4s\n    \n    Non-retryable errors (400, 401, 402, 404, 413, 422) fail immediately\n    because retrying won't fix the underlying problem.\n    \"\"\"\n    for attempt in range(max_retries):\n        try:\n            response = requests.post(\n                f\"{BASE_URL}/videos/generations\",\n                headers=HEADERS,\n                json=payload,\n                timeout=30       # 30s connection timeout\n            )\n\n            # Success — return the task object\n            if response.status_code == 200:\n                return response.json()\n\n            # Parse the error response\n            error = response.json().get(\"error\", {})\n            error_type = error.get(\"type\", \"\")\n            error_msg = error.get(\"message\", \"Unknown error\")\n\n            # Non-retryable errors — fail immediately\n            if response.status_code in (400, 401, 402, 404, 413, 422):\n                raise ValueError(\n                    f\"API error {response.status_code}: {error_msg}\"\n                )\n\n            # Retryable errors — exponential backoff with jitter\n            if response.status_code in (429, 500, 502, 503):\n                wait = (2 ** attempt) + random.uniform(0, 1)\n                print(f\"  Retry {attempt + 1}/{max_retries} \"\n                      f\"after {wait:.1f}s ({error_type}: {error_msg})\")\n                time.sleep(wait)\n                continue\n\n        except requests.exceptions.Timeout:\n            # Server didn't respond within 30 seconds\n            wait = (2 ** attempt) + random.uniform(0, 1)\n            print(f\"  Timeout. Retry {attempt + 1}/{max_retries} \"\n                  f\"after {wait:.1f}s\")\n            time.sleep(wait)\n            continue\n\n        except requests.exceptions.ConnectionError as e:\n            # DNS failure, refused connection, etc.\n            wait = (2 ** attempt) + random.uniform(0, 1)\n            print(f\"  Connection error: {e}. Retry {attempt + 1}/{max_retries} \"\n                  f\"after {wait:.1f}s\")\n            time.sleep(wait)\n            continue\n\n    raise RuntimeError(f\"Failed after {max_retries} retries\")\n",[27,5029,5030,5037,5041,5058,5062,5067,5072,5076,5081,5086,5091,5096,5100,5105,5110,5114,5130,5137,5146,5158,5169,5179,5192,5196,5200,5205,5218,5225,5229,5234,5248,5268,5287,5291,5296,5330,5340,5366,5371,5375,5380,5406,5439,5473,5514,5519,5524,5528,5537,5543,5571,5602,5622,5628,5634,5639,5652,5658,5685,5725,5744,5749,5754,5759],{"__ignoreMap":140},[144,5031,5032,5034],{"class":146,"line":147},[144,5033,346],{"class":257},[144,5035,5036],{"class":261}," random\n",[144,5038,5039],{"class":146,"line":165},[144,5040,375],{"emptyLinePlaceholder":57},[144,5042,5043,5045,5048,5051,5053,5056],{"class":146,"line":177},[144,5044,525],{"class":257},[144,5046,5047],{"class":150}," generate_video_with_retry",[144,5049,5050],{"class":261},"(payload, max_retries",[144,5052,265],{"class":257},[144,5054,5055],{"class":154},"3",[144,5057,547],{"class":261},[144,5059,5060],{"class":146,"line":186},[144,5061,552],{"class":158},[144,5063,5064],{"class":146,"line":372},[144,5065,5066],{"class":158},"    Submit a video generation request with automatic retry\n",[144,5068,5069],{"class":146,"line":378},[144,5070,5071],{"class":158},"    for transient errors (429, 500, 502, 503).\n",[144,5073,5074],{"class":146,"line":384},[144,5075,562],{"class":158},[144,5077,5078],{"class":146,"line":408},[144,5079,5080],{"class":158},"    Uses exponential backoff with jitter to avoid thundering herd:\n",[144,5082,5083],{"class":146,"line":419},[144,5084,5085],{"class":158},"    - Attempt 1: wait ~1s\n",[144,5087,5088],{"class":146,"line":430},[144,5089,5090],{"class":158},"    - Attempt 2: wait ~2s  \n",[144,5092,5093],{"class":146,"line":454},[144,5094,5095],{"class":158},"    - Attempt 3: wait ~4s\n",[144,5097,5098],{"class":146,"line":465},[144,5099,562],{"class":158},[144,5101,5102],{"class":146,"line":599},[144,5103,5104],{"class":158},"    Non-retryable errors (400, 401, 402, 404, 413, 422) fail immediately\n",[144,5106,5107],{"class":146,"line":604},[144,5108,5109],{"class":158},"    because retrying won't fix the underlying problem.\n",[144,5111,5112],{"class":146,"line":610},[144,5113,552],{"class":158},[144,5115,5116,5119,5122,5124,5127],{"class":146,"line":616},[144,5117,5118],{"class":257},"    for",[144,5120,5121],{"class":261}," attempt ",[144,5123,1179],{"class":257},[144,5125,5126],{"class":154}," range",[144,5128,5129],{"class":261},"(max_retries):\n",[144,5131,5132,5135],{"class":146,"line":622},[144,5133,5134],{"class":257},"        try",[144,5136,859],{"class":261},[144,5138,5139,5142,5144],{"class":146,"line":627},[144,5140,5141],{"class":261},"            response ",[144,5143,265],{"class":257},[144,5145,1431],{"class":261},[144,5147,5148,5150,5152,5154,5156],{"class":146,"line":638},[144,5149,917],{"class":257},[144,5151,448],{"class":158},[144,5153,678],{"class":154},[144,5155,1443],{"class":158},[144,5157,451],{"class":261},[144,5159,5160,5163,5165,5167],{"class":146,"line":653},[144,5161,5162],{"class":700},"                headers",[144,5164,265],{"class":257},[144,5166,422],{"class":154},[144,5168,451],{"class":261},[144,5170,5171,5174,5176],{"class":146,"line":659},[144,5172,5173],{"class":700},"                json",[144,5175,265],{"class":257},[144,5177,5178],{"class":261},"payload,\n",[144,5180,5181,5184,5186,5189],{"class":146,"line":670},[144,5182,5183],{"class":700},"                timeout",[144,5185,265],{"class":257},[144,5187,5188],{"class":154},"30",[144,5190,5191],{"class":173},"       # 30s connection timeout\n",[144,5193,5194],{"class":146,"line":697},[144,5195,955],{"class":261},[144,5197,5198],{"class":146,"line":709},[144,5199,375],{"emptyLinePlaceholder":57},[144,5201,5202],{"class":146,"line":715},[144,5203,5204],{"class":173},"            # Success — return the task object\n",[144,5206,5207,5210,5212,5214,5216],{"class":146,"line":721},[144,5208,5209],{"class":257},"            if",[144,5211,2508],{"class":261},[144,5213,853],{"class":257},[144,5215,2513],{"class":154},[144,5217,859],{"class":261},[144,5219,5220,5223],{"class":146,"line":727},[144,5221,5222],{"class":257},"                return",[144,5224,735],{"class":261},[144,5226,5227],{"class":146,"line":738},[144,5228,375],{"emptyLinePlaceholder":57},[144,5230,5231],{"class":146,"line":743},[144,5232,5233],{"class":173},"            # Parse the error response\n",[144,5235,5236,5239,5241,5244,5246],{"class":146,"line":749},[144,5237,5238],{"class":261},"            error ",[144,5240,265],{"class":257},[144,5242,5243],{"class":261}," response.json().get(",[144,5245,896],{"class":158},[144,5247,899],{"class":261},[144,5249,5250,5253,5255,5258,5261,5263,5266],{"class":146,"line":766},[144,5251,5252],{"class":261},"            error_type ",[144,5254,265],{"class":257},[144,5256,5257],{"class":261}," error.get(",[144,5259,5260],{"class":158},"\"type\"",[144,5262,399],{"class":261},[144,5264,5265],{"class":158},"\"\"",[144,5267,405],{"class":261},[144,5269,5270,5273,5275,5277,5280,5282,5285],{"class":146,"line":787},[144,5271,5272],{"class":261},"            error_msg ",[144,5274,265],{"class":257},[144,5276,5257],{"class":261},[144,5278,5279],{"class":158},"\"message\"",[144,5281,399],{"class":261},[144,5283,5284],{"class":158},"\"Unknown error\"",[144,5286,405],{"class":261},[144,5288,5289],{"class":146,"line":833},[144,5290,375],{"emptyLinePlaceholder":57},[144,5292,5293],{"class":146,"line":838},[144,5294,5295],{"class":173},"            # Non-retryable errors — fail immediately\n",[144,5297,5298,5300,5302,5304,5306,5308,5310,5312,5314,5316,5318,5320,5322,5324,5326,5328],{"class":146,"line":844},[144,5299,5209],{"class":257},[144,5301,2508],{"class":261},[144,5303,1179],{"class":257},[144,5305,1217],{"class":261},[144,5307,3636],{"class":154},[144,5309,399],{"class":261},[144,5311,4847],{"class":154},[144,5313,399],{"class":261},[144,5315,4865],{"class":154},[144,5317,399],{"class":261},[144,5319,4883],{"class":154},[144,5321,399],{"class":261},[144,5323,4901],{"class":154},[144,5325,399],{"class":261},[144,5327,4919],{"class":154},[144,5329,547],{"class":261},[144,5331,5332,5335,5338],{"class":146,"line":862},[144,5333,5334],{"class":257},"                raise",[144,5336,5337],{"class":154}," ValueError",[144,5339,911],{"class":261},[144,5341,5342,5345,5348,5350,5353,5355,5357,5359,5362,5364],{"class":146,"line":871},[144,5343,5344],{"class":257},"                    f",[144,5346,5347],{"class":158},"\"API error ",[144,5349,684],{"class":154},[144,5351,5352],{"class":261},"response.status_code",[144,5354,690],{"class":154},[144,5356,436],{"class":158},[144,5358,684],{"class":154},[144,5360,5361],{"class":261},"error_msg",[144,5363,690],{"class":154},[144,5365,949],{"class":158},[144,5367,5368],{"class":146,"line":886},[144,5369,5370],{"class":261},"                )\n",[144,5372,5373],{"class":146,"line":902},[144,5374,375],{"emptyLinePlaceholder":57},[144,5376,5377],{"class":146,"line":914},[144,5378,5379],{"class":173},"            # Retryable errors — exponential backoff with jitter\n",[144,5381,5382,5384,5386,5388,5390,5392,5394,5396,5398,5400,5402,5404],{"class":146,"line":952},[144,5383,5209],{"class":257},[144,5385,2508],{"class":261},[144,5387,1179],{"class":257},[144,5389,1217],{"class":261},[144,5391,4937],{"class":154},[144,5393,399],{"class":261},[144,5395,4958],{"class":154},[144,5397,399],{"class":261},[144,5399,4978],{"class":154},[144,5401,399],{"class":261},[144,5403,4998],{"class":154},[144,5405,547],{"class":261},[144,5407,5408,5411,5413,5415,5418,5421,5424,5427,5430,5432,5434,5437],{"class":146,"line":958},[144,5409,5410],{"class":261},"                wait ",[144,5412,265],{"class":257},[144,5414,1217],{"class":261},[144,5416,5417],{"class":154},"2",[144,5419,5420],{"class":257}," **",[144,5422,5423],{"class":261}," attempt) ",[144,5425,5426],{"class":257},"+",[144,5428,5429],{"class":261}," random.uniform(",[144,5431,782],{"class":154},[144,5433,399],{"class":261},[144,5435,5436],{"class":154},"1",[144,5438,405],{"class":261},[144,5440,5441,5444,5446,5448,5451,5453,5456,5458,5461,5463,5465,5468,5470],{"class":146,"line":963},[144,5442,5443],{"class":154},"                print",[144,5445,793],{"class":261},[144,5447,439],{"class":257},[144,5449,5450],{"class":158},"\"  Retry ",[144,5452,684],{"class":154},[144,5454,5455],{"class":261},"attempt ",[144,5457,5426],{"class":257},[144,5459,5460],{"class":154}," 1}",[144,5462,1225],{"class":158},[144,5464,684],{"class":154},[144,5466,5467],{"class":261},"max_retries",[144,5469,690],{"class":154},[144,5471,5472],{"class":158}," \"\n",[144,5474,5475,5478,5481,5483,5486,5489,5491,5494,5496,5499,5501,5503,5505,5507,5509,5512],{"class":146,"line":969},[144,5476,5477],{"class":257},"                      f",[144,5479,5480],{"class":158},"\"after ",[144,5482,684],{"class":154},[144,5484,5485],{"class":261},"wait",[144,5487,5488],{"class":257},":.1f",[144,5490,690],{"class":154},[144,5492,5493],{"class":158},"s (",[144,5495,684],{"class":154},[144,5497,5498],{"class":261},"error_type",[144,5500,690],{"class":154},[144,5502,436],{"class":158},[144,5504,684],{"class":154},[144,5506,5361],{"class":261},[144,5508,690],{"class":154},[144,5510,5511],{"class":158},")\"",[144,5513,405],{"class":261},[144,5515,5516],{"class":146,"line":975},[144,5517,5518],{"class":261},"                time.sleep(wait)\n",[144,5520,5521],{"class":146,"line":987},[144,5522,5523],{"class":257},"                continue\n",[144,5525,5526],{"class":146,"line":992},[144,5527,375],{"emptyLinePlaceholder":57},[144,5529,5531,5534],{"class":146,"line":5530},48,[144,5532,5533],{"class":257},"        except",[144,5535,5536],{"class":261}," requests.exceptions.Timeout:\n",[144,5538,5540],{"class":146,"line":5539},49,[144,5541,5542],{"class":173},"            # Server didn't respond within 30 seconds\n",[144,5544,5546,5549,5551,5553,5555,5557,5559,5561,5563,5565,5567,5569],{"class":146,"line":5545},50,[144,5547,5548],{"class":261},"            wait ",[144,5550,265],{"class":257},[144,5552,1217],{"class":261},[144,5554,5417],{"class":154},[144,5556,5420],{"class":257},[144,5558,5423],{"class":261},[144,5560,5426],{"class":257},[144,5562,5429],{"class":261},[144,5564,782],{"class":154},[144,5566,399],{"class":261},[144,5568,5436],{"class":154},[144,5570,405],{"class":261},[144,5572,5574,5577,5579,5581,5584,5586,5588,5590,5592,5594,5596,5598,5600],{"class":146,"line":5573},51,[144,5575,5576],{"class":154},"            print",[144,5578,793],{"class":261},[144,5580,439],{"class":257},[144,5582,5583],{"class":158},"\"  Timeout. Retry ",[144,5585,684],{"class":154},[144,5587,5455],{"class":261},[144,5589,5426],{"class":257},[144,5591,5460],{"class":154},[144,5593,1225],{"class":158},[144,5595,684],{"class":154},[144,5597,5467],{"class":261},[144,5599,690],{"class":154},[144,5601,5472],{"class":158},[144,5603,5605,5608,5610,5612,5614,5616,5618,5620],{"class":146,"line":5604},52,[144,5606,5607],{"class":257},"                  f",[144,5609,5480],{"class":158},[144,5611,684],{"class":154},[144,5613,5485],{"class":261},[144,5615,5488],{"class":257},[144,5617,690],{"class":154},[144,5619,1023],{"class":158},[144,5621,405],{"class":261},[144,5623,5625],{"class":146,"line":5624},53,[144,5626,5627],{"class":261},"            time.sleep(wait)\n",[144,5629,5631],{"class":146,"line":5630},54,[144,5632,5633],{"class":257},"            continue\n",[144,5635,5637],{"class":146,"line":5636},55,[144,5638,375],{"emptyLinePlaceholder":57},[144,5640,5642,5644,5647,5649],{"class":146,"line":5641},56,[144,5643,5533],{"class":257},[144,5645,5646],{"class":261}," requests.exceptions.ConnectionError ",[144,5648,1165],{"class":257},[144,5650,5651],{"class":261}," e:\n",[144,5653,5655],{"class":146,"line":5654},57,[144,5656,5657],{"class":173},"            # DNS failure, refused connection, etc.\n",[144,5659,5661,5663,5665,5667,5669,5671,5673,5675,5677,5679,5681,5683],{"class":146,"line":5660},58,[144,5662,5548],{"class":261},[144,5664,265],{"class":257},[144,5666,1217],{"class":261},[144,5668,5417],{"class":154},[144,5670,5420],{"class":257},[144,5672,5423],{"class":261},[144,5674,5426],{"class":257},[144,5676,5429],{"class":261},[144,5678,782],{"class":154},[144,5680,399],{"class":261},[144,5682,5436],{"class":154},[144,5684,405],{"class":261},[144,5686,5688,5690,5692,5694,5697,5699,5702,5704,5707,5709,5711,5713,5715,5717,5719,5721,5723],{"class":146,"line":5687},59,[144,5689,5576],{"class":154},[144,5691,793],{"class":261},[144,5693,439],{"class":257},[144,5695,5696],{"class":158},"\"  Connection error: ",[144,5698,684],{"class":154},[144,5700,5701],{"class":261},"e",[144,5703,690],{"class":154},[144,5705,5706],{"class":158},". Retry ",[144,5708,684],{"class":154},[144,5710,5455],{"class":261},[144,5712,5426],{"class":257},[144,5714,5460],{"class":154},[144,5716,1225],{"class":158},[144,5718,684],{"class":154},[144,5720,5467],{"class":261},[144,5722,690],{"class":154},[144,5724,5472],{"class":158},[144,5726,5728,5730,5732,5734,5736,5738,5740,5742],{"class":146,"line":5727},60,[144,5729,5607],{"class":257},[144,5731,5480],{"class":158},[144,5733,684],{"class":154},[144,5735,5485],{"class":261},[144,5737,5488],{"class":257},[144,5739,690],{"class":154},[144,5741,1023],{"class":158},[144,5743,405],{"class":261},[144,5745,5747],{"class":146,"line":5746},61,[144,5748,5627],{"class":261},[144,5750,5752],{"class":146,"line":5751},62,[144,5753,5633],{"class":257},[144,5755,5757],{"class":146,"line":5756},63,[144,5758,375],{"emptyLinePlaceholder":57},[144,5760,5762,5764,5766,5768,5770,5773,5775,5777,5779,5782],{"class":146,"line":5761},64,[144,5763,995],{"class":257},[144,5765,908],{"class":154},[144,5767,793],{"class":261},[144,5769,439],{"class":257},[144,5771,5772],{"class":158},"\"Failed after ",[144,5774,684],{"class":154},[144,5776,5467],{"class":261},[144,5778,690],{"class":154},[144,5780,5781],{"class":158}," retries\"",[144,5783,405],{"class":261},[10,5785,5786],{},"This handles:",[96,5788,5789,5795,5801,5807,5813],{},[72,5790,5791,5794],{},[22,5792,5793],{},"Rate limits (429)"," — exponential backoff with jitter avoids synchronized retries from multiple clients",[72,5796,5797,5800],{},[22,5798,5799],{},"Server errors (500/502/503)"," — automatic retry with increasing delay",[72,5802,5803,5806],{},[22,5804,5805],{},"Timeouts"," — 30-second timeout prevents hanging on unresponsive servers",[72,5808,5809,5812],{},[22,5810,5811],{},"Connection drops"," — DNS failures, refused connections, network blips",[72,5814,5815,5818],{},[22,5816,5817],{},"Client errors (400/401/402/404/413/422)"," — fail immediately because retrying won't fix bad input",[17,5820,5821],{},[10,5822,5823,5825],{},[22,5824,132],{}," For production systems, consider logging failed requests with their full payload and error response. This makes debugging much easier when things go wrong at 3 AM.",[91,5827,5829],{"id":5828},"validating-input-before-api-calls","Validating Input Before API Calls",[10,5831,5832],{},"Save credits and time by catching obvious errors locally:",[135,5834,5836],{"className":337,"code":5835,"language":339,"meta":140,"style":140},"def validate_payload(payload):\n    \"\"\"\n    Validate a generation payload before sending to the API.\n    Catches common mistakes that would result in 400 errors.\n    \"\"\"\n    errors = []\n    \n    # Required fields\n    if not payload.get(\"model\"):\n        errors.append(\"'model' is required\")\n    if not payload.get(\"prompt\") or not payload[\"prompt\"].strip():\n        errors.append(\"'prompt' is required and cannot be empty\")\n    \n    # Duration range\n    duration = payload.get(\"duration\", 5)\n    if duration \u003C 4 or duration > 15:\n        errors.append(f\"'duration' must be 4-15, got {duration}\")\n    \n    # Quality values\n    valid_qualities = {\"480p\", \"720p\", \"1080p\"}\n    quality = payload.get(\"quality\", \"720p\")\n    if quality not in valid_qualities:\n        errors.append(f\"'quality' must be one of {valid_qualities}, got '{quality}'\")\n    \n    # Aspect ratio values\n    valid_ratios = {\"16:9\", \"9:16\", \"1:1\", \"4:3\", \"3:4\", \"21:9\"}\n    ratio = payload.get(\"aspect_ratio\", \"16:9\")\n    if ratio not in valid_ratios:\n        errors.append(f\"'aspect_ratio' must be one of {valid_ratios}, got '{ratio}'\")\n    \n    # Image URL validation\n    image_urls = payload.get(\"image_urls\", [])\n    if len(image_urls) > 9:\n        errors.append(f\"Maximum 9 images allowed, got {len(image_urls)}\")\n    for i, url in enumerate(image_urls):\n        if not url.startswith((\"http://\", \"https://\")):\n            errors.append(f\"image_urls[{i}] must be an HTTP(S) URL\")\n    \n    if errors:\n        raise ValueError(f\"Payload validation failed:\\n\" + \"\\n\".join(f\"  - {e}\" for e in errors))\n    \n    return True\n",[27,5837,5838,5848,5852,5857,5862,5866,5876,5880,5885,5900,5910,5936,5945,5949,5954,5972,5997,6016,6020,6025,6047,6065,6081,6111,6115,6120,6156,6174,6188,6217,6221,6226,6241,6258,6279,6294,6314,6336,6340,6347,6402,6406],{"__ignoreMap":140},[144,5839,5840,5842,5845],{"class":146,"line":147},[144,5841,525],{"class":257},[144,5843,5844],{"class":150}," validate_payload",[144,5846,5847],{"class":261},"(payload):\n",[144,5849,5850],{"class":146,"line":165},[144,5851,552],{"class":158},[144,5853,5854],{"class":146,"line":177},[144,5855,5856],{"class":158},"    Validate a generation payload before sending to the API.\n",[144,5858,5859],{"class":146,"line":186},[144,5860,5861],{"class":158},"    Catches common mistakes that would result in 400 errors.\n",[144,5863,5864],{"class":146,"line":372},[144,5865,552],{"class":158},[144,5867,5868,5871,5873],{"class":146,"line":378},[144,5869,5870],{"class":261},"    errors ",[144,5872,265],{"class":257},[144,5874,5875],{"class":261}," []\n",[144,5877,5878],{"class":146,"line":384},[144,5879,562],{"class":261},[144,5881,5882],{"class":146,"line":408},[144,5883,5884],{"class":173},"    # Required fields\n",[144,5886,5887,5889,5892,5895,5898],{"class":146,"line":419},[144,5888,2505],{"class":257},[144,5890,5891],{"class":257}," not",[144,5893,5894],{"class":261}," payload.get(",[144,5896,5897],{"class":158},"\"model\"",[144,5899,547],{"class":261},[144,5901,5902,5905,5908],{"class":146,"line":430},[144,5903,5904],{"class":261},"        errors.append(",[144,5906,5907],{"class":158},"\"'model' is required\"",[144,5909,405],{"class":261},[144,5911,5912,5914,5916,5918,5921,5923,5926,5928,5931,5933],{"class":146,"line":454},[144,5913,2505],{"class":257},[144,5915,5891],{"class":257},[144,5917,5894],{"class":261},[144,5919,5920],{"class":158},"\"prompt\"",[144,5922,1162],{"class":261},[144,5924,5925],{"class":257},"or",[144,5927,5891],{"class":257},[144,5929,5930],{"class":261}," payload[",[144,5932,5920],{"class":158},[144,5934,5935],{"class":261},"].strip():\n",[144,5937,5938,5940,5943],{"class":146,"line":465},[144,5939,5904],{"class":261},[144,5941,5942],{"class":158},"\"'prompt' is required and cannot be empty\"",[144,5944,405],{"class":261},[144,5946,5947],{"class":146,"line":599},[144,5948,562],{"class":261},[144,5950,5951],{"class":146,"line":604},[144,5952,5953],{"class":173},"    # Duration range\n",[144,5955,5956,5959,5961,5963,5966,5968,5970],{"class":146,"line":610},[144,5957,5958],{"class":261},"    duration ",[144,5960,265],{"class":257},[144,5962,5894],{"class":261},[144,5964,5965],{"class":158},"\"duration\"",[144,5967,399],{"class":261},[144,5969,1351],{"class":154},[144,5971,405],{"class":261},[144,5973,5974,5976,5979,5981,5984,5987,5989,5992,5995],{"class":146,"line":616},[144,5975,2505],{"class":257},[144,5977,5978],{"class":261}," duration ",[144,5980,647],{"class":257},[144,5982,5983],{"class":154}," 4",[144,5985,5986],{"class":257}," or",[144,5988,5978],{"class":261},[144,5990,5991],{"class":257},">",[144,5993,5994],{"class":154}," 15",[144,5996,859],{"class":261},[144,5998,5999,6001,6003,6006,6008,6010,6012,6014],{"class":146,"line":622},[144,6000,5904],{"class":261},[144,6002,439],{"class":257},[144,6004,6005],{"class":158},"\"'duration' must be 4-15, got ",[144,6007,684],{"class":154},[144,6009,1773],{"class":261},[144,6011,690],{"class":154},[144,6013,448],{"class":158},[144,6015,405],{"class":261},[144,6017,6018],{"class":146,"line":627},[144,6019,562],{"class":261},[144,6021,6022],{"class":146,"line":638},[144,6023,6024],{"class":173},"    # Quality values\n",[144,6026,6027,6030,6032,6035,6037,6039,6041,6043,6045],{"class":146,"line":653},[144,6028,6029],{"class":261},"    valid_qualities ",[144,6031,265],{"class":257},[144,6033,6034],{"class":261}," {",[144,6036,4012],{"class":158},[144,6038,399],{"class":261},[144,6040,1367],{"class":158},[144,6042,399],{"class":261},[144,6044,3709],{"class":158},[144,6046,468],{"class":261},[144,6048,6049,6052,6054,6056,6059,6061,6063],{"class":146,"line":659},[144,6050,6051],{"class":261},"    quality ",[144,6053,265],{"class":257},[144,6055,5894],{"class":261},[144,6057,6058],{"class":158},"\"quality\"",[144,6060,399],{"class":261},[144,6062,1367],{"class":158},[144,6064,405],{"class":261},[144,6066,6067,6069,6072,6075,6078],{"class":146,"line":670},[144,6068,2505],{"class":257},[144,6070,6071],{"class":261}," quality ",[144,6073,6074],{"class":257},"not",[144,6076,6077],{"class":257}," in",[144,6079,6080],{"class":261}," valid_qualities:\n",[144,6082,6083,6085,6087,6090,6092,6095,6097,6100,6102,6104,6106,6109],{"class":146,"line":697},[144,6084,5904],{"class":261},[144,6086,439],{"class":257},[144,6088,6089],{"class":158},"\"'quality' must be one of ",[144,6091,684],{"class":154},[144,6093,6094],{"class":261},"valid_qualities",[144,6096,690],{"class":154},[144,6098,6099],{"class":158},", got '",[144,6101,684],{"class":154},[144,6103,1781],{"class":261},[144,6105,690],{"class":154},[144,6107,6108],{"class":158},"'\"",[144,6110,405],{"class":261},[144,6112,6113],{"class":146,"line":709},[144,6114,562],{"class":261},[144,6116,6117],{"class":146,"line":715},[144,6118,6119],{"class":173},"    # Aspect ratio values\n",[144,6121,6122,6125,6127,6129,6131,6133,6135,6137,6140,6142,6145,6147,6150,6152,6154],{"class":146,"line":721},[144,6123,6124],{"class":261},"    valid_ratios ",[144,6126,265],{"class":257},[144,6128,6034],{"class":261},[144,6130,1383],{"class":158},[144,6132,399],{"class":261},[144,6134,3721],{"class":158},[144,6136,399],{"class":261},[144,6138,6139],{"class":158},"\"1:1\"",[144,6141,399],{"class":261},[144,6143,6144],{"class":158},"\"4:3\"",[144,6146,399],{"class":261},[144,6148,6149],{"class":158},"\"3:4\"",[144,6151,399],{"class":261},[144,6153,3832],{"class":158},[144,6155,468],{"class":261},[144,6157,6158,6161,6163,6165,6168,6170,6172],{"class":146,"line":727},[144,6159,6160],{"class":261},"    ratio ",[144,6162,265],{"class":257},[144,6164,5894],{"class":261},[144,6166,6167],{"class":158},"\"aspect_ratio\"",[144,6169,399],{"class":261},[144,6171,1383],{"class":158},[144,6173,405],{"class":261},[144,6175,6176,6178,6181,6183,6185],{"class":146,"line":738},[144,6177,2505],{"class":257},[144,6179,6180],{"class":261}," ratio ",[144,6182,6074],{"class":257},[144,6184,6077],{"class":257},[144,6186,6187],{"class":261}," valid_ratios:\n",[144,6189,6190,6192,6194,6197,6199,6202,6204,6206,6208,6211,6213,6215],{"class":146,"line":743},[144,6191,5904],{"class":261},[144,6193,439],{"class":257},[144,6195,6196],{"class":158},"\"'aspect_ratio' must be one of ",[144,6198,684],{"class":154},[144,6200,6201],{"class":261},"valid_ratios",[144,6203,690],{"class":154},[144,6205,6099],{"class":158},[144,6207,684],{"class":154},[144,6209,6210],{"class":261},"ratio",[144,6212,690],{"class":154},[144,6214,6108],{"class":158},[144,6216,405],{"class":261},[144,6218,6219],{"class":146,"line":749},[144,6220,562],{"class":261},[144,6222,6223],{"class":146,"line":766},[144,6224,6225],{"class":173},"    # Image URL validation\n",[144,6227,6228,6231,6233,6235,6238],{"class":146,"line":787},[144,6229,6230],{"class":261},"    image_urls ",[144,6232,265],{"class":257},[144,6234,5894],{"class":261},[144,6236,6237],{"class":158},"\"image_urls\"",[144,6239,6240],{"class":261},", [])\n",[144,6242,6243,6245,6248,6251,6253,6256],{"class":146,"line":833},[144,6244,2505],{"class":257},[144,6246,6247],{"class":154}," len",[144,6249,6250],{"class":261},"(image_urls) ",[144,6252,5991],{"class":257},[144,6254,6255],{"class":154}," 9",[144,6257,859],{"class":261},[144,6259,6260,6262,6264,6267,6270,6273,6275,6277],{"class":146,"line":838},[144,6261,5904],{"class":261},[144,6263,439],{"class":257},[144,6265,6266],{"class":158},"\"Maximum 9 images allowed, got ",[144,6268,6269],{"class":154},"{len",[144,6271,6272],{"class":261},"(image_urls)",[144,6274,690],{"class":154},[144,6276,448],{"class":158},[144,6278,405],{"class":261},[144,6280,6281,6283,6286,6288,6291],{"class":146,"line":844},[144,6282,5118],{"class":257},[144,6284,6285],{"class":261}," i, url ",[144,6287,1179],{"class":257},[144,6289,6290],{"class":154}," enumerate",[144,6292,6293],{"class":261},"(image_urls):\n",[144,6295,6296,6298,6300,6303,6306,6308,6311],{"class":146,"line":862},[144,6297,847],{"class":257},[144,6299,5891],{"class":257},[144,6301,6302],{"class":261}," url.startswith((",[144,6304,6305],{"class":158},"\"http://\"",[144,6307,399],{"class":261},[144,6309,6310],{"class":158},"\"https://\"",[144,6312,6313],{"class":261},")):\n",[144,6315,6316,6319,6321,6324,6326,6329,6331,6334],{"class":146,"line":871},[144,6317,6318],{"class":261},"            errors.append(",[144,6320,439],{"class":257},[144,6322,6323],{"class":158},"\"image_urls[",[144,6325,684],{"class":154},[144,6327,6328],{"class":261},"i",[144,6330,690],{"class":154},[144,6332,6333],{"class":158},"] must be an HTTP(S) URL\"",[144,6335,405],{"class":261},[144,6337,6338],{"class":146,"line":886},[144,6339,562],{"class":261},[144,6341,6342,6344],{"class":146,"line":902},[144,6343,2505],{"class":257},[144,6345,6346],{"class":261}," errors:\n",[144,6348,6349,6352,6354,6356,6358,6361,6363,6365,6368,6371,6373,6375,6378,6380,6383,6385,6387,6389,6391,6394,6397,6399],{"class":146,"line":914},[144,6350,6351],{"class":257},"        raise",[144,6353,5337],{"class":154},[144,6355,793],{"class":261},[144,6357,439],{"class":257},[144,6359,6360],{"class":158},"\"Payload validation failed:",[144,6362,1669],{"class":154},[144,6364,448],{"class":158},[144,6366,6367],{"class":257}," +",[144,6369,6370],{"class":158}," \"",[144,6372,1669],{"class":154},[144,6374,448],{"class":158},[144,6376,6377],{"class":261},".join(",[144,6379,439],{"class":257},[144,6381,6382],{"class":158},"\"  - ",[144,6384,684],{"class":154},[144,6386,5701],{"class":261},[144,6388,690],{"class":154},[144,6390,448],{"class":158},[144,6392,6393],{"class":257}," for",[144,6395,6396],{"class":261}," e ",[144,6398,1179],{"class":257},[144,6400,6401],{"class":261}," errors))\n",[144,6403,6404],{"class":146,"line":952},[144,6405,562],{"class":261},[144,6407,6408,6410],{"class":146,"line":958},[144,6409,1702],{"class":257},[144,6411,6412],{"class":154}," True\n",[17,6414,6415],{},[10,6416,6417,6419,6420,6423],{},[22,6418,303],{}," Forgetting to URL-encode special characters in image URLs. If your image path contains spaces or non-ASCII characters, use ",[27,6421,6422],{},"urllib.parse.quote()"," to encode it.",[44,6425],{},[47,6427,6429],{"id":6428},"set-up-webhooks-skip-the-polling","Set Up Webhooks (Skip the Polling)",[10,6431,6432,6433,6436],{},"Polling works fine for scripts and prototyping. For production systems, ",[22,6434,6435],{},"webhooks"," are more efficient — the API pushes the result to your server when the video is ready. No wasted requests, no delay between completion and notification.",[91,6438,6440],{"id":6439},"how-it-works","How It Works",[10,6442,6443,6444,6446],{},"Add ",[27,6445,3600],{}," to your generation request:",[10,6448,6449],{},[2618,6450,6451],{},"Uses the same setup from the first example above.",[135,6453,6455],{"className":337,"code":6454,"language":339,"meta":140,"style":140},"payload = {\n    \"model\": \"seedance-2.0\",\n    \"prompt\": \"A spaceship launches from a desert landscape at sunset.\",\n    \"duration\": 8,\n    \"quality\": \"720p\",\n    \"callback_url\": \"https://your-server.com/api/webhook/seedance\"\n}\n\nresponse = requests.post(\n    f\"{BASE_URL}/videos/generations\",\n    headers=HEADERS,\n    json=payload\n)\ntask = response.json()\nprint(f\"Task submitted: {task['id']}\")\n# No polling needed — your webhook will receive the result\n",[27,6456,6457,6465,6475,6486,6496,6506,6516,6520,6524,6533,6546,6557,6566,6570,6579,6605],{"__ignoreMap":140},[144,6458,6459,6461,6463],{"class":146,"line":147},[144,6460,3660],{"class":261},[144,6462,265],{"class":257},[144,6464,427],{"class":261},[144,6466,6467,6469,6471,6473],{"class":146,"line":165},[144,6468,3669],{"class":158},[144,6470,436],{"class":261},[144,6472,1307],{"class":158},[144,6474,451],{"class":261},[144,6476,6477,6479,6481,6484],{"class":146,"line":177},[144,6478,3680],{"class":158},[144,6480,436],{"class":261},[144,6482,6483],{"class":158},"\"A spaceship launches from a desert landscape at sunset.\"",[144,6485,451],{"class":261},[144,6487,6488,6490,6492,6494],{"class":146,"line":186},[144,6489,3692],{"class":158},[144,6491,436],{"class":261},[144,6493,3697],{"class":154},[144,6495,451],{"class":261},[144,6497,6498,6500,6502,6504],{"class":146,"line":372},[144,6499,3704],{"class":158},[144,6501,436],{"class":261},[144,6503,1367],{"class":158},[144,6505,451],{"class":261},[144,6507,6508,6511,6513],{"class":146,"line":378},[144,6509,6510],{"class":158},"    \"callback_url\"",[144,6512,436],{"class":261},[144,6514,6515],{"class":158},"\"https://your-server.com/api/webhook/seedance\"\n",[144,6517,6518],{"class":146,"line":384},[144,6519,468],{"class":261},[144,6521,6522],{"class":146,"line":408},[144,6523,375],{"emptyLinePlaceholder":57},[144,6525,6526,6529,6531],{"class":146,"line":419},[144,6527,6528],{"class":261},"response ",[144,6530,265],{"class":257},[144,6532,1431],{"class":261},[144,6534,6535,6538,6540,6542,6544],{"class":146,"line":430},[144,6536,6537],{"class":257},"    f",[144,6539,448],{"class":158},[144,6541,678],{"class":154},[144,6543,1443],{"class":158},[144,6545,451],{"class":261},[144,6547,6548,6551,6553,6555],{"class":146,"line":454},[144,6549,6550],{"class":700},"    headers",[144,6552,265],{"class":257},[144,6554,422],{"class":154},[144,6556,451],{"class":261},[144,6558,6559,6562,6564],{"class":146,"line":465},[144,6560,6561],{"class":700},"    json",[144,6563,265],{"class":257},[144,6565,2787],{"class":261},[144,6567,6568],{"class":146,"line":599},[144,6569,405],{"class":261},[144,6571,6572,6575,6577],{"class":146,"line":604},[144,6573,6574],{"class":261},"task ",[144,6576,265],{"class":257},[144,6578,735],{"class":261},[144,6580,6581,6584,6586,6588,6591,6593,6595,6597,6599,6601,6603],{"class":146,"line":610},[144,6582,6583],{"class":154},"print",[144,6585,793],{"class":261},[144,6587,439],{"class":257},[144,6589,6590],{"class":158},"\"Task submitted: ",[144,6592,684],{"class":154},[144,6594,1528],{"class":261},[144,6596,1531],{"class":158},[144,6598,1534],{"class":261},[144,6600,690],{"class":154},[144,6602,448],{"class":158},[144,6604,405],{"class":261},[144,6606,6607],{"class":146,"line":616},[144,6608,6609],{"class":173},"# No polling needed — your webhook will receive the result\n",[10,6611,6612,6613,6615],{},"When the video is ready, the API sends a POST request to your ",[27,6614,3600],{}," with the completed task object — the exact same payload you'd get from polling.",[91,6617,6619],{"id":6618},"webhook-requirements","Webhook Requirements",[2035,6621,6622,6632],{},[2038,6623,6624],{},[2041,6625,6626,6629],{},[2044,6627,6628],{},"Requirement",[2044,6630,6631],{},"Details",[2051,6633,6634,6642,6650,6658,6666,6674],{},[2041,6635,6636,6639],{},[2056,6637,6638],{},"Protocol",[2056,6640,6641],{},"HTTPS only (no HTTP) — required for security",[2041,6643,6644,6647],{},[2056,6645,6646],{},"Response",[2056,6648,6649],{},"Return 2xx within 10 seconds",[2041,6651,6652,6655],{},[2056,6653,6654],{},"Retries",[2056,6656,6657],{},"3 attempts on failure (1s, 2s, 4s intervals)",[2041,6659,6660,6663],{},[2056,6661,6662],{},"URL length",[2056,6664,6665],{},"≤ 2048 characters",[2041,6667,6668,6671],{},[2056,6669,6670],{},"Network",[2056,6672,6673],{},"No internal/private IPs (localhost, 10.x.x.x, 192.168.x.x)",[2041,6675,6676,6679],{},[2056,6677,6678],{},"Body",[2056,6680,6681],{},"JSON POST with the full task object",[91,6683,6685],{"id":6684},"production-flask-webhook-receiver","Production Flask Webhook Receiver",[10,6687,6688],{},"Here's a complete webhook server using Flask with proper validation, error handling, and async video downloading:",[135,6690,6692],{"className":337,"code":6691,"language":339,"meta":140,"style":140},"# webhook_server.py\n\"\"\"\nSeedance webhook receiver — handles video completion callbacks.\nRun: pip install flask requests\n      python webhook_server.py\n\"\"\"\nfrom flask import Flask, request, jsonify\nimport json\nimport os\nimport threading\nimport requests as req  # renamed to avoid conflict with flask.request\n\napp = Flask(__name__)\n\n# Directory to save completed videos\nOUTPUT_DIR = os.getenv(\"VIDEO_OUTPUT_DIR\", \"./videos\")\nos.makedirs(OUTPUT_DIR, exist_ok=True)\n\n\ndef download_video_async(video_url, task_id):\n    \"\"\"Download video in a background thread to not block the webhook response.\"\"\"\n    try:\n        filename = os.path.join(OUTPUT_DIR, f\"{task_id}.mp4\")\n        print(f\"  Downloading {task_id} to {filename}...\")\n        resp = req.get(video_url, stream=True, timeout=120)\n        resp.raise_for_status()\n        with open(filename, \"wb\") as f:\n            for chunk in resp.iter_content(chunk_size=8192):\n                f.write(chunk)\n        size_mb = os.path.getsize(filename) / (1024 * 1024)\n        print(f\"  Saved: {filename} ({size_mb:.1f} MB)\")\n    except Exception as e:\n        print(f\"  Download failed for {task_id}: {e}\")\n\n\n@app.route(\"/api/webhook/seedance\", methods=[\"POST\"])\ndef handle_webhook():\n    \"\"\"\n    Handle Seedance video completion webhook.\n    \n    The API sends a POST with the full task object when\n    a video generation completes (success or failure).\n    \"\"\"\n    # Parse the incoming task object\n    task = request.json\n    if not task:\n        return jsonify({\"error\": \"Empty body\"}), 400\n    \n    task_id = task.get(\"id\", \"unknown\")\n    status = task.get(\"status\", \"unknown\")\n    model = task.get(\"model\", \"unknown\")\n\n    print(f\"\\n{'='*50}\")\n    print(f\"Webhook received: task={task_id}\")\n    print(f\"  Status: {status}\")\n    print(f\"  Model: {model}\")\n\n    if status == \"completed\":\n        # Extract video URL(s) from results\n        results = task.get(\"results\", [])\n        if results:\n            video_url = results[0]\n            print(f\"  Video URL: {video_url}\")\n            \n            # Download in background thread so we respond quickly\n            thread = threading.Thread(\n                target=download_video_async,\n                args=(video_url, task_id)\n            )\n            thread.start()\n        else:\n            print(f\"  WARNING: Completed but no results array!\")\n\n    elif status == \"failed\":\n        error_info = task.get(\"error\", {})\n        print(f\"  FAILED: {json.dumps(error_info, indent=2)}\")\n        # TODO: Log to your error tracking system (Sentry, etc.)\n        # TODO: Optionally retry the generation with modified parameters\n\n    else:\n        print(f\"  Unexpected status: {status}\")\n        print(f\"  Full payload: {json.dumps(task, indent=2)}\")\n\n    # Always return 200 quickly — the API expects a response within 10s\n    return jsonify({\"received\": True, \"task_id\": task_id}), 200\n\n\n@app.route(\"/health\", methods=[\"GET\"])\ndef health_check():\n    \"\"\"Health check endpoint for load balancers.\"\"\"\n    return jsonify({\"status\": \"ok\"}), 200\n\n\nif __name__ == \"__main__\":\n    print(f\"Starting webhook server...\")\n    print(f\"Videos will be saved to: {os.path.abspath(OUTPUT_DIR)}\")\n    print(f\"Webhook URL: http://localhost:5000/api/webhook/seedance\")\n    app.run(host=\"0.0.0.0\", port=5000, debug=True)\n",[27,6693,6694,6699,6704,6709,6714,6719,6723,6736,6742,6748,6755,6770,6774,6789,6793,6798,6817,6835,6839,6843,6853,6858,6865,6894,6924,6951,6956,6973,6992,6997,7021,7054,7067,7096,7100,7104,7129,7138,7142,7147,7151,7156,7161,7165,7170,7179,7188,7209,7213,7231,7248,7265,7269,7295,7316,7337,7358,7362,7374,7379,7392,7399,7413,7434,7439,7445,7456,7467,7478,7483,7489,7497,7511,7516,7530,7544,7576,7588,7598,7603,7610,7632,7663,7668,7674,7699,7704,7709,7732,7742,7748,7766,7771,7776,7789,7803,7830,7844],{"__ignoreMap":140},[144,6695,6696],{"class":146,"line":147},[144,6697,6698],{"class":173},"# webhook_server.py\n",[144,6700,6701],{"class":146,"line":165},[144,6702,6703],{"class":158},"\"\"\"\n",[144,6705,6706],{"class":146,"line":177},[144,6707,6708],{"class":158},"Seedance webhook receiver — handles video completion callbacks.\n",[144,6710,6711],{"class":146,"line":186},[144,6712,6713],{"class":158},"Run: pip install flask requests\n",[144,6715,6716],{"class":146,"line":372},[144,6717,6718],{"class":158},"      python webhook_server.py\n",[144,6720,6721],{"class":146,"line":378},[144,6722,6703],{"class":158},[144,6724,6725,6728,6731,6733],{"class":146,"line":384},[144,6726,6727],{"class":257},"from",[144,6729,6730],{"class":261}," flask ",[144,6732,346],{"class":257},[144,6734,6735],{"class":261}," Flask, request, jsonify\n",[144,6737,6738,6740],{"class":146,"line":408},[144,6739,346],{"class":257},[144,6741,369],{"class":261},[144,6743,6744,6746],{"class":146,"line":419},[144,6745,346],{"class":257},[144,6747,362],{"class":261},[144,6749,6750,6752],{"class":146,"line":430},[144,6751,346],{"class":257},[144,6753,6754],{"class":261}," threading\n",[144,6756,6757,6759,6762,6764,6767],{"class":146,"line":454},[144,6758,346],{"class":257},[144,6760,6761],{"class":261}," requests ",[144,6763,1165],{"class":257},[144,6765,6766],{"class":261}," req  ",[144,6768,6769],{"class":173},"# renamed to avoid conflict with flask.request\n",[144,6771,6772],{"class":146,"line":465},[144,6773,375],{"emptyLinePlaceholder":57},[144,6775,6776,6779,6781,6784,6787],{"class":146,"line":599},[144,6777,6778],{"class":261},"app ",[144,6780,265],{"class":257},[144,6782,6783],{"class":261}," Flask(",[144,6785,6786],{"class":154},"__name__",[144,6788,405],{"class":261},[144,6790,6791],{"class":146,"line":604},[144,6792,375],{"emptyLinePlaceholder":57},[144,6794,6795],{"class":146,"line":610},[144,6796,6797],{"class":173},"# Directory to save completed videos\n",[144,6799,6800,6803,6805,6807,6810,6812,6815],{"class":146,"line":616},[144,6801,6802],{"class":154},"OUTPUT_DIR",[144,6804,390],{"class":257},[144,6806,393],{"class":261},[144,6808,6809],{"class":158},"\"VIDEO_OUTPUT_DIR\"",[144,6811,399],{"class":261},[144,6813,6814],{"class":158},"\"./videos\"",[144,6816,405],{"class":261},[144,6818,6819,6822,6824,6826,6829,6831,6833],{"class":146,"line":622},[144,6820,6821],{"class":261},"os.makedirs(",[144,6823,6802],{"class":154},[144,6825,399],{"class":261},[144,6827,6828],{"class":700},"exist_ok",[144,6830,265],{"class":257},[144,6832,1138],{"class":154},[144,6834,405],{"class":261},[144,6836,6837],{"class":146,"line":627},[144,6838,375],{"emptyLinePlaceholder":57},[144,6840,6841],{"class":146,"line":638},[144,6842,375],{"emptyLinePlaceholder":57},[144,6844,6845,6847,6850],{"class":146,"line":653},[144,6846,525],{"class":257},[144,6848,6849],{"class":150}," download_video_async",[144,6851,6852],{"class":261},"(video_url, task_id):\n",[144,6854,6855],{"class":146,"line":659},[144,6856,6857],{"class":158},"    \"\"\"Download video in a background thread to not block the webhook response.\"\"\"\n",[144,6859,6860,6863],{"class":146,"line":670},[144,6861,6862],{"class":257},"    try",[144,6864,859],{"class":261},[144,6866,6867,6870,6872,6875,6877,6879,6881,6883,6885,6887,6889,6892],{"class":146,"line":697},[144,6868,6869],{"class":261},"        filename ",[144,6871,265],{"class":257},[144,6873,6874],{"class":261}," os.path.join(",[144,6876,6802],{"class":154},[144,6878,399],{"class":261},[144,6880,439],{"class":257},[144,6882,448],{"class":158},[144,6884,684],{"class":154},[144,6886,687],{"class":261},[144,6888,690],{"class":154},[144,6890,6891],{"class":158},".mp4\"",[144,6893,405],{"class":261},[144,6895,6896,6898,6900,6902,6905,6907,6909,6911,6914,6916,6918,6920,6922],{"class":146,"line":709},[144,6897,790],{"class":154},[144,6899,793],{"class":261},[144,6901,439],{"class":257},[144,6903,6904],{"class":158},"\"  Downloading ",[144,6906,684],{"class":154},[144,6908,687],{"class":261},[144,6910,690],{"class":154},[144,6912,6913],{"class":158}," to ",[144,6915,684],{"class":154},[144,6917,1113],{"class":261},[144,6919,690],{"class":154},[144,6921,1118],{"class":158},[144,6923,405],{"class":261},[144,6925,6926,6929,6931,6934,6936,6938,6940,6942,6944,6946,6949],{"class":146,"line":715},[144,6927,6928],{"class":261},"        resp ",[144,6930,265],{"class":257},[144,6932,6933],{"class":261}," req.get(video_url, ",[144,6935,1133],{"class":700},[144,6937,265],{"class":257},[144,6939,1138],{"class":154},[144,6941,399],{"class":261},[144,6943,1018],{"class":700},[144,6945,265],{"class":257},[144,6947,6948],{"class":154},"120",[144,6950,405],{"class":261},[144,6952,6953],{"class":146,"line":721},[144,6954,6955],{"class":261},"        resp.raise_for_status()\n",[144,6957,6958,6961,6963,6965,6967,6969,6971],{"class":146,"line":727},[144,6959,6960],{"class":257},"        with",[144,6962,1153],{"class":154},[144,6964,1156],{"class":261},[144,6966,1159],{"class":158},[144,6968,1162],{"class":261},[144,6970,1165],{"class":257},[144,6972,1168],{"class":261},[144,6974,6975,6978,6980,6982,6984,6986,6988,6990],{"class":146,"line":738},[144,6976,6977],{"class":257},"            for",[144,6979,1176],{"class":261},[144,6981,1179],{"class":257},[144,6983,1182],{"class":261},[144,6985,1185],{"class":700},[144,6987,265],{"class":257},[144,6989,1190],{"class":154},[144,6991,547],{"class":261},[144,6993,6994],{"class":146,"line":743},[144,6995,6996],{"class":261},"                f.write(chunk)\n",[144,6998,6999,7002,7004,7007,7009,7011,7014,7017,7019],{"class":146,"line":749},[144,7000,7001],{"class":261},"        size_mb ",[144,7003,265],{"class":257},[144,7005,7006],{"class":261}," os.path.getsize(filename) ",[144,7008,1225],{"class":257},[144,7010,1217],{"class":261},[144,7012,7013],{"class":154},"1024",[144,7015,7016],{"class":257}," *",[144,7018,1228],{"class":154},[144,7020,405],{"class":261},[144,7022,7023,7025,7027,7029,7032,7034,7036,7038,7040,7042,7045,7047,7049,7052],{"class":146,"line":766},[144,7024,790],{"class":154},[144,7026,793],{"class":261},[144,7028,439],{"class":257},[144,7030,7031],{"class":158},"\"  Saved: ",[144,7033,684],{"class":154},[144,7035,1113],{"class":261},[144,7037,690],{"class":154},[144,7039,1217],{"class":158},[144,7041,684],{"class":154},[144,7043,7044],{"class":261},"size_mb",[144,7046,5488],{"class":257},[144,7048,690],{"class":154},[144,7050,7051],{"class":158}," MB)\"",[144,7053,405],{"class":261},[144,7055,7056,7059,7062,7065],{"class":146,"line":787},[144,7057,7058],{"class":257},"    except",[144,7060,7061],{"class":154}," Exception",[144,7063,7064],{"class":257}," as",[144,7066,5651],{"class":261},[144,7068,7069,7071,7073,7075,7078,7080,7082,7084,7086,7088,7090,7092,7094],{"class":146,"line":833},[144,7070,790],{"class":154},[144,7072,793],{"class":261},[144,7074,439],{"class":257},[144,7076,7077],{"class":158},"\"  Download failed for ",[144,7079,684],{"class":154},[144,7081,687],{"class":261},[144,7083,690],{"class":154},[144,7085,436],{"class":158},[144,7087,684],{"class":154},[144,7089,5701],{"class":261},[144,7091,690],{"class":154},[144,7093,448],{"class":158},[144,7095,405],{"class":261},[144,7097,7098],{"class":146,"line":838},[144,7099,375],{"emptyLinePlaceholder":57},[144,7101,7102],{"class":146,"line":844},[144,7103,375],{"emptyLinePlaceholder":57},[144,7105,7106,7109,7111,7114,7116,7119,7121,7124,7127],{"class":146,"line":862},[144,7107,7108],{"class":150},"@app.route",[144,7110,793],{"class":261},[144,7112,7113],{"class":158},"\"/api/webhook/seedance\"",[144,7115,399],{"class":261},[144,7117,7118],{"class":700},"methods",[144,7120,265],{"class":257},[144,7122,7123],{"class":261},"[",[144,7125,7126],{"class":158},"\"POST\"",[144,7128,1628],{"class":261},[144,7130,7131,7133,7136],{"class":146,"line":871},[144,7132,525],{"class":257},[144,7134,7135],{"class":150}," handle_webhook",[144,7137,1288],{"class":261},[144,7139,7140],{"class":146,"line":886},[144,7141,552],{"class":158},[144,7143,7144],{"class":146,"line":902},[144,7145,7146],{"class":158},"    Handle Seedance video completion webhook.\n",[144,7148,7149],{"class":146,"line":914},[144,7150,562],{"class":158},[144,7152,7153],{"class":146,"line":952},[144,7154,7155],{"class":158},"    The API sends a POST with the full task object when\n",[144,7157,7158],{"class":146,"line":958},[144,7159,7160],{"class":158},"    a video generation completes (success or failure).\n",[144,7162,7163],{"class":146,"line":963},[144,7164,552],{"class":158},[144,7166,7167],{"class":146,"line":969},[144,7168,7169],{"class":173},"    # Parse the incoming task object\n",[144,7171,7172,7174,7176],{"class":146,"line":975},[144,7173,1495],{"class":261},[144,7175,265],{"class":257},[144,7177,7178],{"class":261}," request.json\n",[144,7180,7181,7183,7185],{"class":146,"line":987},[144,7182,2505],{"class":257},[144,7184,5891],{"class":257},[144,7186,7187],{"class":261}," task:\n",[144,7189,7190,7193,7196,7198,7200,7203,7206],{"class":146,"line":992},[144,7191,7192],{"class":257},"        return",[144,7194,7195],{"class":261}," jsonify({",[144,7197,896],{"class":158},[144,7199,436],{"class":261},[144,7201,7202],{"class":158},"\"Empty body\"",[144,7204,7205],{"class":261},"}), ",[144,7207,7208],{"class":154},"400\n",[144,7210,7211],{"class":146,"line":5530},[144,7212,562],{"class":261},[144,7214,7215,7218,7220,7222,7224,7226,7229],{"class":146,"line":5539},[144,7216,7217],{"class":261},"    task_id ",[144,7219,265],{"class":257},[144,7221,774],{"class":261},[144,7223,1625],{"class":158},[144,7225,399],{"class":261},[144,7227,7228],{"class":158},"\"unknown\"",[144,7230,405],{"class":261},[144,7232,7233,7236,7238,7240,7242,7244,7246],{"class":146,"line":5545},[144,7234,7235],{"class":261},"    status ",[144,7237,265],{"class":257},[144,7239,774],{"class":261},[144,7241,760],{"class":158},[144,7243,399],{"class":261},[144,7245,7228],{"class":158},[144,7247,405],{"class":261},[144,7249,7250,7253,7255,7257,7259,7261,7263],{"class":146,"line":5573},[144,7251,7252],{"class":261},"    model ",[144,7254,265],{"class":257},[144,7256,774],{"class":261},[144,7258,5897],{"class":158},[144,7260,399],{"class":261},[144,7262,7228],{"class":158},[144,7264,405],{"class":261},[144,7266,7267],{"class":146,"line":5604},[144,7268,375],{"emptyLinePlaceholder":57},[144,7270,7271,7273,7275,7277,7279,7282,7285,7288,7291,7293],{"class":146,"line":5624},[144,7272,1101],{"class":154},[144,7274,793],{"class":261},[144,7276,439],{"class":257},[144,7278,448],{"class":158},[144,7280,7281],{"class":154},"\\n{",[144,7283,7284],{"class":158},"'='",[144,7286,7287],{"class":257},"*",[144,7289,7290],{"class":154},"50}",[144,7292,448],{"class":158},[144,7294,405],{"class":261},[144,7296,7297,7299,7301,7303,7306,7308,7310,7312,7314],{"class":146,"line":5630},[144,7298,1101],{"class":154},[144,7300,793],{"class":261},[144,7302,439],{"class":257},[144,7304,7305],{"class":158},"\"Webhook received: task=",[144,7307,684],{"class":154},[144,7309,687],{"class":261},[144,7311,690],{"class":154},[144,7313,448],{"class":158},[144,7315,405],{"class":261},[144,7317,7318,7320,7322,7324,7327,7329,7331,7333,7335],{"class":146,"line":5636},[144,7319,1101],{"class":154},[144,7321,793],{"class":261},[144,7323,439],{"class":257},[144,7325,7326],{"class":158},"\"  Status: ",[144,7328,684],{"class":154},[144,7330,813],{"class":261},[144,7332,690],{"class":154},[144,7334,448],{"class":158},[144,7336,405],{"class":261},[144,7338,7339,7341,7343,7345,7348,7350,7352,7354,7356],{"class":146,"line":5641},[144,7340,1101],{"class":154},[144,7342,793],{"class":261},[144,7344,439],{"class":257},[144,7346,7347],{"class":158},"\"  Model: ",[144,7349,684],{"class":154},[144,7351,1746],{"class":261},[144,7353,690],{"class":154},[144,7355,448],{"class":158},[144,7357,405],{"class":261},[144,7359,7360],{"class":146,"line":5654},[144,7361,375],{"emptyLinePlaceholder":57},[144,7363,7364,7366,7368,7370,7372],{"class":146,"line":5660},[144,7365,2505],{"class":257},[144,7367,850],{"class":261},[144,7369,853],{"class":257},[144,7371,856],{"class":158},[144,7373,859],{"class":261},[144,7375,7376],{"class":146,"line":5687},[144,7377,7378],{"class":173},"        # Extract video URL(s) from results\n",[144,7380,7381,7384,7386,7388,7390],{"class":146,"line":5727},[144,7382,7383],{"class":261},"        results ",[144,7385,265],{"class":257},[144,7387,774],{"class":261},[144,7389,1650],{"class":158},[144,7391,6240],{"class":261},[144,7393,7394,7396],{"class":146,"line":5746},[144,7395,847],{"class":257},[144,7397,7398],{"class":261}," results:\n",[144,7400,7401,7404,7406,7409,7411],{"class":146,"line":5751},[144,7402,7403],{"class":261},"            video_url ",[144,7405,265],{"class":257},[144,7407,7408],{"class":261}," results[",[144,7410,782],{"class":154},[144,7412,763],{"class":261},[144,7414,7415,7417,7419,7421,7424,7426,7428,7430,7432],{"class":146,"line":5756},[144,7416,5576],{"class":154},[144,7418,793],{"class":261},[144,7420,439],{"class":257},[144,7422,7423],{"class":158},"\"  Video URL: ",[144,7425,684],{"class":154},[144,7427,1677],{"class":261},[144,7429,690],{"class":154},[144,7431,448],{"class":158},[144,7433,405],{"class":261},[144,7435,7436],{"class":146,"line":5761},[144,7437,7438],{"class":261},"            \n",[144,7440,7442],{"class":146,"line":7441},65,[144,7443,7444],{"class":173},"            # Download in background thread so we respond quickly\n",[144,7446,7448,7451,7453],{"class":146,"line":7447},66,[144,7449,7450],{"class":261},"            thread ",[144,7452,265],{"class":257},[144,7454,7455],{"class":261}," threading.Thread(\n",[144,7457,7459,7462,7464],{"class":146,"line":7458},67,[144,7460,7461],{"class":700},"                target",[144,7463,265],{"class":257},[144,7465,7466],{"class":261},"download_video_async,\n",[144,7468,7470,7473,7475],{"class":146,"line":7469},68,[144,7471,7472],{"class":700},"                args",[144,7474,265],{"class":257},[144,7476,7477],{"class":261},"(video_url, task_id)\n",[144,7479,7481],{"class":146,"line":7480},69,[144,7482,955],{"class":261},[144,7484,7486],{"class":146,"line":7485},70,[144,7487,7488],{"class":261},"            thread.start()\n",[144,7490,7492,7495],{"class":146,"line":7491},71,[144,7493,7494],{"class":257},"        else",[144,7496,859],{"class":261},[144,7498,7500,7502,7504,7506,7509],{"class":146,"line":7499},72,[144,7501,5576],{"class":154},[144,7503,793],{"class":261},[144,7505,439],{"class":257},[144,7507,7508],{"class":158},"\"  WARNING: Completed but no results array!\"",[144,7510,405],{"class":261},[144,7512,7514],{"class":146,"line":7513},73,[144,7515,375],{"emptyLinePlaceholder":57},[144,7517,7519,7522,7524,7526,7528],{"class":146,"line":7518},74,[144,7520,7521],{"class":257},"    elif",[144,7523,850],{"class":261},[144,7525,853],{"class":257},[144,7527,881],{"class":158},[144,7529,859],{"class":261},[144,7531,7533,7536,7538,7540,7542],{"class":146,"line":7532},75,[144,7534,7535],{"class":261},"        error_info ",[144,7537,265],{"class":257},[144,7539,774],{"class":261},[144,7541,896],{"class":158},[144,7543,899],{"class":261},[144,7545,7547,7549,7551,7553,7556,7558,7561,7564,7566,7568,7570,7572,7574],{"class":146,"line":7546},76,[144,7548,790],{"class":154},[144,7550,793],{"class":261},[144,7552,439],{"class":257},[144,7554,7555],{"class":158},"\"  FAILED: ",[144,7557,684],{"class":154},[144,7559,7560],{"class":261},"json.dumps(error_info, ",[144,7562,7563],{"class":700},"indent",[144,7565,265],{"class":257},[144,7567,5417],{"class":154},[144,7569,107],{"class":261},[144,7571,690],{"class":154},[144,7573,448],{"class":158},[144,7575,405],{"class":261},[144,7577,7579,7582,7585],{"class":146,"line":7578},77,[144,7580,7581],{"class":173},"        # ",[144,7583,7584],{"class":257},"TODO",[144,7586,7587],{"class":173},": Log to your error tracking system (Sentry, etc.)\n",[144,7589,7591,7593,7595],{"class":146,"line":7590},78,[144,7592,7581],{"class":173},[144,7594,7584],{"class":257},[144,7596,7597],{"class":173},": Optionally retry the generation with modified parameters\n",[144,7599,7601],{"class":146,"line":7600},79,[144,7602,375],{"emptyLinePlaceholder":57},[144,7604,7606,7608],{"class":146,"line":7605},80,[144,7607,2541],{"class":257},[144,7609,859],{"class":261},[144,7611,7613,7615,7617,7619,7622,7624,7626,7628,7630],{"class":146,"line":7612},81,[144,7614,790],{"class":154},[144,7616,793],{"class":261},[144,7618,439],{"class":257},[144,7620,7621],{"class":158},"\"  Unexpected status: ",[144,7623,684],{"class":154},[144,7625,813],{"class":261},[144,7627,690],{"class":154},[144,7629,448],{"class":158},[144,7631,405],{"class":261},[144,7633,7635,7637,7639,7641,7644,7646,7649,7651,7653,7655,7657,7659,7661],{"class":146,"line":7634},82,[144,7636,790],{"class":154},[144,7638,793],{"class":261},[144,7640,439],{"class":257},[144,7642,7643],{"class":158},"\"  Full payload: ",[144,7645,684],{"class":154},[144,7647,7648],{"class":261},"json.dumps(task, ",[144,7650,7563],{"class":700},[144,7652,265],{"class":257},[144,7654,5417],{"class":154},[144,7656,107],{"class":261},[144,7658,690],{"class":154},[144,7660,448],{"class":158},[144,7662,405],{"class":261},[144,7664,7666],{"class":146,"line":7665},83,[144,7667,375],{"emptyLinePlaceholder":57},[144,7669,7671],{"class":146,"line":7670},84,[144,7672,7673],{"class":173},"    # Always return 200 quickly — the API expects a response within 10s\n",[144,7675,7677,7679,7681,7684,7686,7688,7690,7693,7696],{"class":146,"line":7676},85,[144,7678,1702],{"class":257},[144,7680,7195],{"class":261},[144,7682,7683],{"class":158},"\"received\"",[144,7685,436],{"class":261},[144,7687,1138],{"class":154},[144,7689,399],{"class":261},[144,7691,7692],{"class":158},"\"task_id\"",[144,7694,7695],{"class":261},": task_id}), ",[144,7697,7698],{"class":154},"200\n",[144,7700,7702],{"class":146,"line":7701},86,[144,7703,375],{"emptyLinePlaceholder":57},[144,7705,7707],{"class":146,"line":7706},87,[144,7708,375],{"emptyLinePlaceholder":57},[144,7710,7712,7714,7716,7719,7721,7723,7725,7727,7730],{"class":146,"line":7711},88,[144,7713,7108],{"class":150},[144,7715,793],{"class":261},[144,7717,7718],{"class":158},"\"/health\"",[144,7720,399],{"class":261},[144,7722,7118],{"class":700},[144,7724,265],{"class":257},[144,7726,7123],{"class":261},[144,7728,7729],{"class":158},"\"GET\"",[144,7731,1628],{"class":261},[144,7733,7735,7737,7740],{"class":146,"line":7734},89,[144,7736,525],{"class":257},[144,7738,7739],{"class":150}," health_check",[144,7741,1288],{"class":261},[144,7743,7745],{"class":146,"line":7744},90,[144,7746,7747],{"class":158},"    \"\"\"Health check endpoint for load balancers.\"\"\"\n",[144,7749,7751,7753,7755,7757,7759,7762,7764],{"class":146,"line":7750},91,[144,7752,1702],{"class":257},[144,7754,7195],{"class":261},[144,7756,760],{"class":158},[144,7758,436],{"class":261},[144,7760,7761],{"class":158},"\"ok\"",[144,7763,7205],{"class":261},[144,7765,7698],{"class":154},[144,7767,7769],{"class":146,"line":7768},92,[144,7770,375],{"emptyLinePlaceholder":57},[144,7772,7774],{"class":146,"line":7773},93,[144,7775,375],{"emptyLinePlaceholder":57},[144,7777,7779,7781,7783,7785,7787],{"class":146,"line":7778},94,[144,7780,1718],{"class":257},[144,7782,1721],{"class":154},[144,7784,1724],{"class":257},[144,7786,1727],{"class":158},[144,7788,859],{"class":261},[144,7790,7792,7794,7796,7798,7801],{"class":146,"line":7791},95,[144,7793,1101],{"class":154},[144,7795,793],{"class":261},[144,7797,439],{"class":257},[144,7799,7800],{"class":158},"\"Starting webhook server...\"",[144,7802,405],{"class":261},[144,7804,7806,7808,7810,7812,7815,7817,7820,7822,7824,7826,7828],{"class":146,"line":7805},96,[144,7807,1101],{"class":154},[144,7809,793],{"class":261},[144,7811,439],{"class":257},[144,7813,7814],{"class":158},"\"Videos will be saved to: ",[144,7816,684],{"class":154},[144,7818,7819],{"class":261},"os.path.abspath(",[144,7821,6802],{"class":154},[144,7823,107],{"class":261},[144,7825,690],{"class":154},[144,7827,448],{"class":158},[144,7829,405],{"class":261},[144,7831,7833,7835,7837,7839,7842],{"class":146,"line":7832},97,[144,7834,1101],{"class":154},[144,7836,793],{"class":261},[144,7838,439],{"class":257},[144,7840,7841],{"class":158},"\"Webhook URL: http://localhost:5000/api/webhook/seedance\"",[144,7843,405],{"class":261},[144,7845,7847,7850,7853,7855,7858,7860,7863,7865,7868,7870,7873,7875,7877],{"class":146,"line":7846},98,[144,7848,7849],{"class":261},"    app.run(",[144,7851,7852],{"class":700},"host",[144,7854,265],{"class":257},[144,7856,7857],{"class":158},"\"0.0.0.0\"",[144,7859,399],{"class":261},[144,7861,7862],{"class":700},"port",[144,7864,265],{"class":257},[144,7866,7867],{"class":154},"5000",[144,7869,399],{"class":261},[144,7871,7872],{"class":700},"debug",[144,7874,265],{"class":257},[144,7876,1138],{"class":154},[144,7878,405],{"class":261},[10,7880,7881],{},"Install dependencies and run:",[135,7883,7885],{"className":137,"code":7884,"language":139,"meta":140,"style":140},"pip install flask requests\npython webhook_server.py\n",[27,7886,7887,7898],{"__ignoreMap":140},[144,7888,7889,7891,7893,7896],{"class":146,"line":147},[144,7890,189],{"class":150},[144,7892,192],{"class":158},[144,7894,7895],{"class":158}," flask",[144,7897,327],{"class":158},[144,7899,7900,7902],{"class":146,"line":165},[144,7901,339],{"class":150},[144,7903,7904],{"class":158}," webhook_server.py\n",[10,7906,7907],{},"Key design decisions in this server:",[96,7909,7910,7920,7930],{},[72,7911,7912,7915,7916,7919],{},[22,7913,7914],{},"Background downloads"," — We spawn a thread to download the video so the webhook handler returns ",[27,7917,7918],{},"200"," immediately. The API expects a response within 10 seconds; video downloads can take longer.",[72,7921,7922,7925,7926,7929],{},[22,7923,7924],{},"Health check endpoint"," — ",[27,7927,7928],{},"/health"," is useful when deploying behind a load balancer (ALB, nginx, etc.).",[72,7931,7932,7935],{},[22,7933,7934],{},"Error logging"," — Failed tasks are printed with the full error payload. In production, pipe this to Sentry, Datadog, or your logging stack.",[91,7937,7939],{"id":7938},"exposing-localhost-with-ngrok","Exposing Localhost with ngrok",[10,7941,7942,7943,7948],{},"For local development, use ",[36,7944,7947],{"href":7945,"rel":7946},"https://ngrok.com",[40],"ngrok"," to create a public HTTPS URL that tunnels to your local server:",[135,7950,7952],{"className":137,"code":7951,"language":139,"meta":140,"style":140},"# Install ngrok (macOS)\nbrew install ngrok\n\n# Or download from https://ngrok.com/download\n\n# Start the tunnel\nngrok http 5000\n",[27,7953,7954,7959,7969,7973,7978,7982,7987],{"__ignoreMap":140},[144,7955,7956],{"class":146,"line":147},[144,7957,7958],{"class":173},"# Install ngrok (macOS)\n",[144,7960,7961,7964,7966],{"class":146,"line":165},[144,7962,7963],{"class":150},"brew",[144,7965,192],{"class":158},[144,7967,7968],{"class":158}," ngrok\n",[144,7970,7971],{"class":146,"line":177},[144,7972,375],{"emptyLinePlaceholder":57},[144,7974,7975],{"class":146,"line":186},[144,7976,7977],{"class":173},"# Or download from https://ngrok.com/download\n",[144,7979,7980],{"class":146,"line":372},[144,7981,375],{"emptyLinePlaceholder":57},[144,7983,7984],{"class":146,"line":378},[144,7985,7986],{"class":173},"# Start the tunnel\n",[144,7988,7989,7991,7994],{"class":146,"line":384},[144,7990,7947],{"class":150},[144,7992,7993],{"class":158}," http",[144,7995,7996],{"class":154}," 5000\n",[10,7998,7999],{},"ngrok outputs something like:",[135,8001,8004],{"className":8002,"code":8003,"language":2184},[2182],"Forwarding  https://a1b2c3d4.ngrok-free.app → http://localhost:5000\n",[27,8005,8003],{"__ignoreMap":140},[10,8007,8008,8009,8011],{},"Use that HTTPS URL as your ",[27,8010,3600],{},":",[135,8013,8015],{"className":337,"code":8014,"language":339,"meta":140,"style":140},"payload = {\n    \"model\": \"seedance-2.0\",\n    \"prompt\": \"Your prompt here\",\n    \"callback_url\": \"https://a1b2c3d4.ngrok-free.app/api/webhook/seedance\"\n}\n",[27,8016,8017,8025,8035,8046,8055],{"__ignoreMap":140},[144,8018,8019,8021,8023],{"class":146,"line":147},[144,8020,3660],{"class":261},[144,8022,265],{"class":257},[144,8024,427],{"class":261},[144,8026,8027,8029,8031,8033],{"class":146,"line":165},[144,8028,3669],{"class":158},[144,8030,436],{"class":261},[144,8032,1307],{"class":158},[144,8034,451],{"class":261},[144,8036,8037,8039,8041,8044],{"class":146,"line":177},[144,8038,3680],{"class":158},[144,8040,436],{"class":261},[144,8042,8043],{"class":158},"\"Your prompt here\"",[144,8045,451],{"class":261},[144,8047,8048,8050,8052],{"class":146,"line":186},[144,8049,6510],{"class":158},[144,8051,436],{"class":261},[144,8053,8054],{"class":158},"\"https://a1b2c3d4.ngrok-free.app/api/webhook/seedance\"\n",[144,8056,8057],{"class":146,"line":372},[144,8058,468],{"class":261},[17,8060,8061],{},[10,8062,8063,8065,8066,8069,8070,8073],{},[22,8064,303],{}," Using the ",[27,8067,8068],{},"http://"," ngrok URL instead of ",[27,8071,8072],{},"https://",". The Seedance API requires HTTPS for webhooks — it will reject plain HTTP callback URLs with a 400 error.",[91,8075,8077],{"id":8076},"webhook-security","Webhook Security",[10,8079,8080],{},"In production, validate that webhook requests actually come from the EvoLink API:",[135,8082,8084],{"className":337,"code":8083,"language":339,"meta":140,"style":140},"import hmac\nimport hashlib\n\ndef verify_webhook(request):\n    \"\"\"Verify webhook authenticity using the task ID pattern.\"\"\"\n    task = request.json\n    task_id = task.get(\"id\", \"\")\n    \n    # EvoLink task IDs follow a specific format\n    if not task_id.startswith(\"task-unified-\"):\n        return False\n    \n    # Additional validation: check required fields exist\n    required_fields = [\"id\", \"status\", \"model\", \"created\"]\n    if not all(field in task for field in required_fields):\n        return False\n    \n    return True\n",[27,8085,8086,8093,8100,8104,8114,8119,8127,8143,8147,8152,8166,8173,8177,8182,8209,8237,8243,8247],{"__ignoreMap":140},[144,8087,8088,8090],{"class":146,"line":147},[144,8089,346],{"class":257},[144,8091,8092],{"class":261}," hmac\n",[144,8094,8095,8097],{"class":146,"line":165},[144,8096,346],{"class":257},[144,8098,8099],{"class":261}," hashlib\n",[144,8101,8102],{"class":146,"line":177},[144,8103,375],{"emptyLinePlaceholder":57},[144,8105,8106,8108,8111],{"class":146,"line":186},[144,8107,525],{"class":257},[144,8109,8110],{"class":150}," verify_webhook",[144,8112,8113],{"class":261},"(request):\n",[144,8115,8116],{"class":146,"line":372},[144,8117,8118],{"class":158},"    \"\"\"Verify webhook authenticity using the task ID pattern.\"\"\"\n",[144,8120,8121,8123,8125],{"class":146,"line":378},[144,8122,1495],{"class":261},[144,8124,265],{"class":257},[144,8126,7178],{"class":261},[144,8128,8129,8131,8133,8135,8137,8139,8141],{"class":146,"line":384},[144,8130,7217],{"class":261},[144,8132,265],{"class":257},[144,8134,774],{"class":261},[144,8136,1625],{"class":158},[144,8138,399],{"class":261},[144,8140,5265],{"class":158},[144,8142,405],{"class":261},[144,8144,8145],{"class":146,"line":408},[144,8146,562],{"class":261},[144,8148,8149],{"class":146,"line":419},[144,8150,8151],{"class":173},"    # EvoLink task IDs follow a specific format\n",[144,8153,8154,8156,8158,8161,8164],{"class":146,"line":430},[144,8155,2505],{"class":257},[144,8157,5891],{"class":257},[144,8159,8160],{"class":261}," task_id.startswith(",[144,8162,8163],{"class":158},"\"task-unified-\"",[144,8165,547],{"class":261},[144,8167,8168,8170],{"class":146,"line":454},[144,8169,7192],{"class":257},[144,8171,8172],{"class":154}," False\n",[144,8174,8175],{"class":146,"line":465},[144,8176,562],{"class":261},[144,8178,8179],{"class":146,"line":599},[144,8180,8181],{"class":173},"    # Additional validation: check required fields exist\n",[144,8183,8184,8187,8189,8192,8194,8196,8198,8200,8202,8204,8207],{"class":146,"line":604},[144,8185,8186],{"class":261},"    required_fields ",[144,8188,265],{"class":257},[144,8190,8191],{"class":261}," [",[144,8193,1625],{"class":158},[144,8195,399],{"class":261},[144,8197,760],{"class":158},[144,8199,399],{"class":261},[144,8201,5897],{"class":158},[144,8203,399],{"class":261},[144,8205,8206],{"class":158},"\"created\"",[144,8208,763],{"class":261},[144,8210,8211,8213,8215,8218,8221,8223,8226,8229,8232,8234],{"class":146,"line":610},[144,8212,2505],{"class":257},[144,8214,5891],{"class":257},[144,8216,8217],{"class":154}," all",[144,8219,8220],{"class":261},"(field ",[144,8222,1179],{"class":257},[144,8224,8225],{"class":261}," task ",[144,8227,8228],{"class":257},"for",[144,8230,8231],{"class":261}," field ",[144,8233,1179],{"class":257},[144,8235,8236],{"class":261}," required_fields):\n",[144,8238,8239,8241],{"class":146,"line":616},[144,8240,7192],{"class":257},[144,8242,8172],{"class":154},[144,8244,8245],{"class":146,"line":622},[144,8246,562],{"class":261},[144,8248,8249,8251],{"class":146,"line":627},[144,8250,1702],{"class":257},[144,8252,6412],{"class":154},[91,8254,8256],{"id":8255},"when-to-use-webhooks-vs-polling","When to Use Webhooks vs Polling",[2035,8258,8259,8272],{},[2038,8260,8261],{},[2041,8262,8263,8266,8269],{},[2044,8264,8265],{},"Scenario",[2044,8267,8268],{},"Recommendation",[2044,8270,8271],{},"Why",[2051,8273,8274,8285,8296,8307,8317,8327],{},[2041,8275,8276,8279,8282],{},[2056,8277,8278],{},"Quick prototyping / scripts",[2056,8280,8281],{},"Polling",[2056,8283,8284],{},"Simpler, no server needed",[2041,8286,8287,8290,8293],{},[2056,8288,8289],{},"Production web app",[2056,8291,8292],{},"Webhooks",[2056,8294,8295],{},"Scalable, no wasted requests",[2041,8297,8298,8301,8304],{},[2056,8299,8300],{},"Batch processing (100+ videos)",[2056,8302,8303],{},"Webhooks + queue",[2056,8305,8306],{},"Submit all, process as they complete",[2041,8308,8309,8312,8314],{},[2056,8310,8311],{},"CLI tools",[2056,8313,8281],{},[2056,8315,8316],{},"No server infrastructure required",[2041,8318,8319,8322,8324],{},[2056,8320,8321],{},"Mobile app backend",[2056,8323,8292],{},[2056,8325,8326],{},"Push notifications to users on completion",[2041,8328,8329,8332,8334],{},[2056,8330,8331],{},"Serverless (Lambda/Cloud Functions)",[2056,8333,8292],{},[2056,8335,8336],{},"Perfect fit — function triggered per completion",[17,8338,8339],{},[10,8340,8341,8343],{},[22,8342,132],{}," For batch processing, combine webhooks with a message queue (Redis, RabbitMQ, SQS). Submit all generation requests, then process completions as they arrive on the queue. This decouples submission from processing and handles retries gracefully.",[44,8345],{},[47,8347,8349],{"id":8348},"batch-processing-generate-multiple-videos","Batch Processing: Generate Multiple Videos",[10,8351,8352],{},"Real-world use cases often involve generating many videos. Here's a pattern for batch processing with rate limiting:",[10,8354,8355],{},[2618,8356,8357],{},"Uses the same setup and helper functions from the first example above.",[135,8359,8361],{"className":337,"code":8360,"language":339,"meta":140,"style":140},"import concurrent.futures\n\ndef batch_generate(prompts, max_concurrent=3):\n    \"\"\"\n    Generate multiple videos with controlled concurrency.\n    \n    Args:\n        prompts: List of prompt strings.\n        max_concurrent: Maximum simultaneous generations.\n    \n    Returns:\n        List of (prompt, result_or_error) tuples.\n    \"\"\"\n    results = []\n    \n    def generate_one(prompt, index):\n        \"\"\"Generate a single video and return the result.\"\"\"\n        payload = {\n            \"model\": \"seedance-2.0\",\n            \"prompt\": prompt,\n            \"duration\": 5,\n            \"quality\": \"720p\"\n        }\n        try:\n            task = generate_video_with_retry(payload)\n            print(f\"[{index}] Submitted: {task['id']}\")\n            result = wait_for_video(task[\"id\"])\n            video_url = result[\"results\"][0]\n            download_video(video_url, f\"batch_{index}.mp4\")\n            return (prompt, result)\n        except Exception as e:\n            print(f\"[{index}] Failed: {e}\")\n            return (prompt, str(e))\n    \n    # Process in batches to respect rate limits\n    with concurrent.futures.ThreadPoolExecutor(max_workers=max_concurrent) as executor:\n        futures = {\n            executor.submit(generate_one, prompt, i): i\n            for i, prompt in enumerate(prompts)\n        }\n        for future in concurrent.futures.as_completed(futures):\n            results.append(future.result())\n    \n    # Summary\n    succeeded = sum(1 for _, r in results if isinstance(r, dict))\n    print(f\"\\nBatch complete: {succeeded}/{len(prompts)} succeeded\")\n    return results\n\n\n# Example usage\nprompts = [\n    \"A hummingbird hovering near a red flower. Macro lens, shallow depth of field.\",\n    \"Ocean waves crashing on volcanic rocks at sunset. Slow motion.\",\n    \"A street musician playing violin in the rain. Cinematic lighting.\",\n]\nbatch_generate(prompts, max_concurrent=2)\n",[27,8362,8363,8370,8374,8390,8394,8399,8403,8407,8412,8417,8421,8425,8430,8434,8443,8447,8458,8463,8472,8483,8491,8502,8512,8517,8523,8533,8568,8581,8597,8617,8624,8634,8663,8676,8680,8685,8705,8714,8719,8733,8737,8749,8754,8758,8763,8801,8837,8844,8848,8852,8857,8867,8874,8881,8888,8892],{"__ignoreMap":140},[144,8364,8365,8367],{"class":146,"line":147},[144,8366,346],{"class":257},[144,8368,8369],{"class":261}," concurrent.futures\n",[144,8371,8372],{"class":146,"line":165},[144,8373,375],{"emptyLinePlaceholder":57},[144,8375,8376,8378,8381,8384,8386,8388],{"class":146,"line":177},[144,8377,525],{"class":257},[144,8379,8380],{"class":150}," batch_generate",[144,8382,8383],{"class":261},"(prompts, max_concurrent",[144,8385,265],{"class":257},[144,8387,5055],{"class":154},[144,8389,547],{"class":261},[144,8391,8392],{"class":146,"line":186},[144,8393,552],{"class":158},[144,8395,8396],{"class":146,"line":372},[144,8397,8398],{"class":158},"    Generate multiple videos with controlled concurrency.\n",[144,8400,8401],{"class":146,"line":378},[144,8402,562],{"class":158},[144,8404,8405],{"class":146,"line":384},[144,8406,567],{"class":158},[144,8408,8409],{"class":146,"line":408},[144,8410,8411],{"class":158},"        prompts: List of prompt strings.\n",[144,8413,8414],{"class":146,"line":419},[144,8415,8416],{"class":158},"        max_concurrent: Maximum simultaneous generations.\n",[144,8418,8419],{"class":146,"line":430},[144,8420,562],{"class":158},[144,8422,8423],{"class":146,"line":454},[144,8424,591],{"class":158},[144,8426,8427],{"class":146,"line":465},[144,8428,8429],{"class":158},"        List of (prompt, result_or_error) tuples.\n",[144,8431,8432],{"class":146,"line":599},[144,8433,552],{"class":158},[144,8435,8436,8439,8441],{"class":146,"line":604},[144,8437,8438],{"class":261},"    results ",[144,8440,265],{"class":257},[144,8442,5875],{"class":261},[144,8444,8445],{"class":146,"line":610},[144,8446,562],{"class":261},[144,8448,8449,8452,8455],{"class":146,"line":616},[144,8450,8451],{"class":257},"    def",[144,8453,8454],{"class":150}," generate_one",[144,8456,8457],{"class":261},"(prompt, index):\n",[144,8459,8460],{"class":146,"line":622},[144,8461,8462],{"class":158},"        \"\"\"Generate a single video and return the result.\"\"\"\n",[144,8464,8465,8468,8470],{"class":146,"line":627},[144,8466,8467],{"class":261},"        payload ",[144,8469,265],{"class":257},[144,8471,427],{"class":261},[144,8473,8474,8477,8479,8481],{"class":146,"line":638},[144,8475,8476],{"class":158},"            \"model\"",[144,8478,436],{"class":261},[144,8480,1307],{"class":158},[144,8482,451],{"class":261},[144,8484,8485,8488],{"class":146,"line":653},[144,8486,8487],{"class":158},"            \"prompt\"",[144,8489,8490],{"class":261},": prompt,\n",[144,8492,8493,8496,8498,8500],{"class":146,"line":659},[144,8494,8495],{"class":158},"            \"duration\"",[144,8497,436],{"class":261},[144,8499,1351],{"class":154},[144,8501,451],{"class":261},[144,8503,8504,8507,8509],{"class":146,"line":670},[144,8505,8506],{"class":158},"            \"quality\"",[144,8508,436],{"class":261},[144,8510,8511],{"class":158},"\"720p\"\n",[144,8513,8514],{"class":146,"line":697},[144,8515,8516],{"class":261},"        }\n",[144,8518,8519,8521],{"class":146,"line":709},[144,8520,5134],{"class":257},[144,8522,859],{"class":261},[144,8524,8525,8528,8530],{"class":146,"line":715},[144,8526,8527],{"class":261},"            task ",[144,8529,265],{"class":257},[144,8531,8532],{"class":261}," generate_video_with_retry(payload)\n",[144,8534,8535,8537,8539,8541,8544,8546,8549,8551,8554,8556,8558,8560,8562,8564,8566],{"class":146,"line":721},[144,8536,5576],{"class":154},[144,8538,793],{"class":261},[144,8540,439],{"class":257},[144,8542,8543],{"class":158},"\"[",[144,8545,684],{"class":154},[144,8547,8548],{"class":261},"index",[144,8550,690],{"class":154},[144,8552,8553],{"class":158},"] Submitted: ",[144,8555,684],{"class":154},[144,8557,1528],{"class":261},[144,8559,1531],{"class":158},[144,8561,1534],{"class":261},[144,8563,690],{"class":154},[144,8565,448],{"class":158},[144,8567,405],{"class":261},[144,8569,8570,8573,8575,8577,8579],{"class":146,"line":727},[144,8571,8572],{"class":261},"            result ",[144,8574,265],{"class":257},[144,8576,1622],{"class":261},[144,8578,1625],{"class":158},[144,8580,1628],{"class":261},[144,8582,8583,8585,8587,8589,8591,8593,8595],{"class":146,"line":738},[144,8584,7403],{"class":261},[144,8586,265],{"class":257},[144,8588,1647],{"class":261},[144,8590,1650],{"class":158},[144,8592,1561],{"class":261},[144,8594,782],{"class":154},[144,8596,763],{"class":261},[144,8598,8599,8602,8604,8607,8609,8611,8613,8615],{"class":146,"line":743},[144,8600,8601],{"class":261},"            download_video(video_url, ",[144,8603,439],{"class":257},[144,8605,8606],{"class":158},"\"batch_",[144,8608,684],{"class":154},[144,8610,8548],{"class":261},[144,8612,690],{"class":154},[144,8614,6891],{"class":158},[144,8616,405],{"class":261},[144,8618,8619,8621],{"class":146,"line":749},[144,8620,865],{"class":257},[144,8622,8623],{"class":261}," (prompt, result)\n",[144,8625,8626,8628,8630,8632],{"class":146,"line":766},[144,8627,5533],{"class":257},[144,8629,7061],{"class":154},[144,8631,7064],{"class":257},[144,8633,5651],{"class":261},[144,8635,8636,8638,8640,8642,8644,8646,8648,8650,8653,8655,8657,8659,8661],{"class":146,"line":787},[144,8637,5576],{"class":154},[144,8639,793],{"class":261},[144,8641,439],{"class":257},[144,8643,8543],{"class":158},[144,8645,684],{"class":154},[144,8647,8548],{"class":261},[144,8649,690],{"class":154},[144,8651,8652],{"class":158},"] Failed: ",[144,8654,684],{"class":154},[144,8656,5701],{"class":261},[144,8658,690],{"class":154},[144,8660,448],{"class":158},[144,8662,405],{"class":261},[144,8664,8665,8667,8670,8673],{"class":146,"line":833},[144,8666,865],{"class":257},[144,8668,8669],{"class":261}," (prompt, ",[144,8671,8672],{"class":154},"str",[144,8674,8675],{"class":261},"(e))\n",[144,8677,8678],{"class":146,"line":838},[144,8679,562],{"class":261},[144,8681,8682],{"class":146,"line":844},[144,8683,8684],{"class":173},"    # Process in batches to respect rate limits\n",[144,8686,8687,8689,8692,8695,8697,8700,8702],{"class":146,"line":862},[144,8688,1150],{"class":257},[144,8690,8691],{"class":261}," concurrent.futures.ThreadPoolExecutor(",[144,8693,8694],{"class":700},"max_workers",[144,8696,265],{"class":257},[144,8698,8699],{"class":261},"max_concurrent) ",[144,8701,1165],{"class":257},[144,8703,8704],{"class":261}," executor:\n",[144,8706,8707,8710,8712],{"class":146,"line":871},[144,8708,8709],{"class":261},"        futures ",[144,8711,265],{"class":257},[144,8713,427],{"class":261},[144,8715,8716],{"class":146,"line":886},[144,8717,8718],{"class":261},"            executor.submit(generate_one, prompt, i): i\n",[144,8720,8721,8723,8726,8728,8730],{"class":146,"line":902},[144,8722,6977],{"class":257},[144,8724,8725],{"class":261}," i, prompt ",[144,8727,1179],{"class":257},[144,8729,6290],{"class":154},[144,8731,8732],{"class":261},"(prompts)\n",[144,8734,8735],{"class":146,"line":914},[144,8736,8516],{"class":261},[144,8738,8739,8741,8744,8746],{"class":146,"line":952},[144,8740,1173],{"class":257},[144,8742,8743],{"class":261}," future ",[144,8745,1179],{"class":257},[144,8747,8748],{"class":261}," concurrent.futures.as_completed(futures):\n",[144,8750,8751],{"class":146,"line":958},[144,8752,8753],{"class":261},"            results.append(future.result())\n",[144,8755,8756],{"class":146,"line":963},[144,8757,562],{"class":261},[144,8759,8760],{"class":146,"line":969},[144,8761,8762],{"class":173},"    # Summary\n",[144,8764,8765,8768,8770,8773,8775,8777,8779,8782,8784,8787,8789,8792,8795,8798],{"class":146,"line":975},[144,8766,8767],{"class":261},"    succeeded ",[144,8769,265],{"class":257},[144,8771,8772],{"class":154}," sum",[144,8774,793],{"class":261},[144,8776,5436],{"class":154},[144,8778,6393],{"class":257},[144,8780,8781],{"class":261}," _, r ",[144,8783,1179],{"class":257},[144,8785,8786],{"class":261}," results ",[144,8788,1718],{"class":257},[144,8790,8791],{"class":154}," isinstance",[144,8793,8794],{"class":261},"(r, ",[144,8796,8797],{"class":154},"dict",[144,8799,8800],{"class":261},"))\n",[144,8802,8803,8805,8807,8809,8811,8813,8816,8818,8821,8823,8825,8827,8830,8832,8835],{"class":146,"line":987},[144,8804,1101],{"class":154},[144,8806,793],{"class":261},[144,8808,439],{"class":257},[144,8810,448],{"class":158},[144,8812,1669],{"class":154},[144,8814,8815],{"class":158},"Batch complete: ",[144,8817,684],{"class":154},[144,8819,8820],{"class":261},"succeeded",[144,8822,690],{"class":154},[144,8824,1225],{"class":158},[144,8826,6269],{"class":154},[144,8828,8829],{"class":261},"(prompts)",[144,8831,690],{"class":154},[144,8833,8834],{"class":158}," succeeded\"",[144,8836,405],{"class":261},[144,8838,8839,8841],{"class":146,"line":992},[144,8840,1702],{"class":257},[144,8842,8843],{"class":261}," results\n",[144,8845,8846],{"class":146,"line":5530},[144,8847,375],{"emptyLinePlaceholder":57},[144,8849,8850],{"class":146,"line":5539},[144,8851,375],{"emptyLinePlaceholder":57},[144,8853,8854],{"class":146,"line":5545},[144,8855,8856],{"class":173},"# Example usage\n",[144,8858,8859,8862,8864],{"class":146,"line":5573},[144,8860,8861],{"class":261},"prompts ",[144,8863,265],{"class":257},[144,8865,8866],{"class":261}," [\n",[144,8868,8869,8872],{"class":146,"line":5604},[144,8870,8871],{"class":158},"    \"A hummingbird hovering near a red flower. Macro lens, shallow depth of field.\"",[144,8873,451],{"class":261},[144,8875,8876,8879],{"class":146,"line":5624},[144,8877,8878],{"class":158},"    \"Ocean waves crashing on volcanic rocks at sunset. Slow motion.\"",[144,8880,451],{"class":261},[144,8882,8883,8886],{"class":146,"line":5630},[144,8884,8885],{"class":158},"    \"A street musician playing violin in the rain. Cinematic lighting.\"",[144,8887,451],{"class":261},[144,8889,8890],{"class":146,"line":5636},[144,8891,763],{"class":261},[144,8893,8894,8897,8900,8902,8904],{"class":146,"line":5641},[144,8895,8896],{"class":261},"batch_generate(prompts, ",[144,8898,8899],{"class":700},"max_concurrent",[144,8901,265],{"class":257},[144,8903,5417],{"class":154},[144,8905,405],{"class":261},[10,8907,8908],{},"Key considerations for batch processing:",[96,8910,8911,8919,8925],{},[72,8912,8913,8918],{},[22,8914,8915],{},[27,8916,8917],{},"max_concurrent=3"," — Don't submit too many requests simultaneously. Start with 2–3 and increase based on your rate limits.",[72,8920,8921,8924],{},[22,8922,8923],{},"ThreadPoolExecutor"," — Uses threads (not processes) because we're I/O-bound (waiting for API responses), not CPU-bound.",[72,8926,8927,8930],{},[22,8928,8929],{},"Error isolation"," — Each video generation is independent. One failure doesn't stop the batch.",[44,8932],{},[47,8934,8936],{"id":8935},"whats-next","What's Next",[10,8938,8939],{},"You've covered the fundamentals — text-to-video, image-to-video, async polling, webhooks, error handling, and batch processing. Here's where to go deeper:",[91,8941,8943],{"id":8942},"explore-advanced-features","Explore Advanced Features",[96,8945,8946,8954,8961,8969,8977],{},[72,8947,8948,8953],{},[22,8949,8950],{},[36,8951,8952],{"href":2965},"@Tags Multimodal Reference Guide"," — Master the @Image, @Video, @Audio reference system for multi-modal generation",[72,8955,8956,8960],{},[22,8957,8958],{},[36,8959,3856],{"href":3855}," — Replicate Hitchcock zooms, one-take tracking shots, and orbital cameras programmatically",[72,8962,8963,8968],{},[22,8964,8965],{},[36,8966,8967],{"href":3380},"Image-to-Video Deep Dive"," — First-last frame control, multi-image composition, e-commerce product videos",[72,8970,8971,8976],{},[22,8972,8973],{},[36,8974,8975],{"href":2612},"E-commerce Product Video Guide"," — Turn product photos into marketing videos at scale",[72,8978,8979,8983],{},[22,8980,8981],{},[36,8982,1766],{"href":1765}," — Shot-script format, timing syntax, and the prompts behind our demo videos",[91,8985,8987],{"id":8986},"reference-docs","Reference Docs",[96,8989,8990,8996,9003],{},[72,8991,8992],{},[36,8993,8995],{"href":1257,"rel":8994},[40],"Video Generation API Reference",[72,8997,8998],{},[36,8999,9002],{"href":9000,"rel":9001},"https://seedance2api.app/docs/multimodal-reference",[40],"Multimodal Reference Specs",[72,9004,9005],{},[36,9006,9009],{"href":9007,"rel":9008},"https://seedance2api.app/docs/sdks",[40],"Python & Node.js SDKs",[91,9011,9013],{"id":9012},"build-something","Build Something",[10,9015,9016],{},"Combine what you've learned. Here are a few project ideas:",[96,9018,9019,9028,9034,9043],{},[72,9020,9021,9024,9025,107],{},[22,9022,9023],{},"Automated product video pipeline"," — Upload product photos, generate marketing videos in bulk (see our ",[36,9026,9027],{"href":2612},"E-commerce Video Guide",[72,9029,9030,9033],{},[22,9031,9032],{},"Social media content engine"," — Generate short-form vertical videos from text briefs, post directly to TikTok/Reels",[72,9035,9036,9039,9040],{},[22,9037,9038],{},"Storyboard-to-video tool"," — Turn sequential images into animated scenes with ",[36,9041,9042],{"href":3855},"camera movement control",[72,9044,9045,9048],{},[22,9046,9047],{},"AI video editing pipeline"," — Use Seedance 2.0's video extension to create longer narratives from shorter clips",[10,9050,9051],{},[22,9052,9053,9054,9058],{},"Ready to build? ",[36,9055,9057],{"href":38,"rel":9056},[40],"Get your free EvoLink API key"," and start generating videos today.",[44,9060],{},[47,9062,9064],{"id":9063},"frequently-asked-questions","Frequently Asked Questions",[91,9066,9068],{"id":9067},"how-long-does-seedance-20-video-generation-take","How long does Seedance 2.0 video generation take?",[10,9070,9071,9072,9074],{},"Typically 30–120 seconds depending on duration and quality settings. A 5-second 720p video completes in about 50 seconds. A 15-second 1080p video can take 2–3 minutes. The API returns an ",[27,9073,2104],{}," field with each task so you can set appropriate timeouts. During peak hours, queue wait times may add 10–30 seconds to the total.",[91,9076,9078],{"id":9077},"what-image-formats-does-the-seedance-20-api-accept","What image formats does the Seedance 2.0 API accept?",[10,9080,9081,9082,9084],{},"JPEG, PNG, WebP, BMP, TIFF, and GIF. Each image must be under 30 MB. You can pass up to 9 images per request via the ",[27,9083,2895],{}," parameter. Images must be publicly accessible URLs — the API fetches them directly. For best results, use images that are at least 720px on the shorter side. Very low-resolution images (below 256px) may produce blurry animations.",[91,9086,9088],{"id":9087},"can-i-generate-videos-longer-than-15-seconds","Can I generate videos longer than 15 seconds?",[10,9090,9091,9092,9094],{},"The maximum single generation is 15 seconds. For longer content, generate multiple clips and concatenate them using FFmpeg or any video editor. Seedance 2.0 supports video extension — you can use a generated video's last frame as the first frame of the next generation to create seamless continuity. Here's the basic approach: generate clip 1, extract the last frame, pass it as ",[27,9093,2993],{}," for clip 2.",[91,9096,9098],{"id":9097},"how-much-does-seedance-20-api-cost-through-evolink","How much does Seedance 2.0 API cost through EvoLink?",[10,9100,9101,9102,9106,9107,9109],{},"Pricing is based on video duration and quality tier. A 5-second 720p video costs approximately 18 credits. EvoLink provides ",[36,9103,9105],{"href":210,"rel":9104},[40],"smart routing"," that can reduce costs compared to direct API access. Check your dashboard for current per-second rates. The ",[27,9108,2114],{}," field in the API response shows the exact cost before generation begins — you'll never be charged more than that amount.",[91,9111,9113],{"id":9112},"whats-the-difference-between-seedance-15-pro-and-seedance-20","What's the difference between seedance-1.5-pro and seedance-2.0?",[10,9115,9116,9117,9119,9120,9122,9123,9127],{},"Seedance 2.0 adds multimodal references (mix images, videos, and audio as inputs), native audio generation, improved physics and consistency, and video editing capabilities. The API interface is identical — same endpoint, same parameters, same response format. You can test with ",[27,9118,29],{}," today and switch to ",[27,9121,1750],{}," by changing the model name. Key 1.5 limitations: single image input only (no @Image2–9), no video/audio references, no native audio generation. See the ",[36,9124,9126],{"href":9125},"/blog/seedance-2-vs-sora-2-api-comparison","Seedance 2.0 vs Sora 2 comparison"," for benchmarks.",[91,9129,9131],{"id":9130},"how-do-i-handle-the-content-rejected-by-safety-filter-error","How do I handle the \"content rejected by safety filter\" error?",[10,9133,9134,9135,9137,9138,9141],{},"The content moderation system rejects prompts involving realistic violence, explicit content, and real public figures. It also rejects realistic human face images uploaded via ",[27,9136,2895],{},". To work around face restrictions, use illustrated, stylized, or anime-style character images. For prompt rejections, rephrase to be less specific about restricted topics. The error response includes ",[27,9139,9140],{},"type: \"content_policy_violation\""," — check for this in your error handling code to give users a clear message.",[91,9143,9145],{"id":9144},"can-i-use-the-seedance-api-in-a-nodejs-javascript-project","Can I use the Seedance API in a Node.js / JavaScript project?",[10,9147,9148,9149,279,9152,9155,9156,9160],{},"Yes. The REST API is language-agnostic — any HTTP client works. The concepts in this tutorial (async polling, webhooks, error handling) apply directly to Node.js with ",[27,9150,9151],{},"fetch",[27,9153,9154],{},"axios",". EvoLink also provides official ",[36,9157,9159],{"href":9007,"rel":9158},[40],"Node.js and Python SDKs"," that handle polling and retries for you.",[91,9162,9164],{"id":9163},"what-happens-if-my-webhook-server-is-down-when-the-video-completes","What happens if my webhook server is down when the video completes?",[10,9166,9167,9168,9171],{},"The API retries webhook delivery 3 times with increasing intervals (1s, 2s, 4s). If all 3 retries fail, the webhook is abandoned — but the video is still available. You can always fall back to polling with ",[27,9169,9170],{},"GET /v1/tasks/{task_id}"," to retrieve the result. For this reason, it's good practice to store the task ID on submission and have a background job that periodically checks for any tasks that completed but weren't received via webhook.",[91,9173,9175],{"id":9174},"is-there-a-rate-limit-on-api-requests","Is there a rate limit on API requests?",[10,9177,9178,9179,9181,9182,9186,9187,9191],{},"Yes. The default rate limit is generous for development and moderate production use. If you hit a ",[27,9180,4937],{}," error, implement exponential backoff as shown in the ",[36,9183,9185],{"href":9184},"#handle-errors-gracefully","error handling section",". For high-volume use cases (thousands of videos per day), contact ",[36,9188,9190],{"href":210,"rel":9189},[40],"EvoLink support"," to discuss custom rate limits and dedicated capacity.",[91,9193,9195],{"id":9194},"can-i-use-seedance-20-for-commercial-projects","Can I use Seedance 2.0 for commercial projects?",[10,9197,9198,9199,9203],{},"Yes. Videos generated through the EvoLink API are licensed for commercial use. You own the output and can use it in products, marketing materials, client deliverables, and published content. See the ",[36,9200,9202],{"href":9201},"/blog/seedance-2-copyright-api-guide","Seedance 2.0 copyright guide"," for detailed licensing terms and best practices for commercial use.",[44,9205],{},[47,9207,9209],{"id":9208},"complete-script","Complete Script",[10,9211,9212],{},"Here's the full tutorial code in a single file — copy, paste, add your API key, and run:",[135,9214,9216],{"className":337,"code":9215,"language":339,"meta":140,"style":140},"\"\"\"\nSeedance 2.0 API Tutorial — Complete Script\nDocs: https://seedance2api.app/docs/video-generation\nAPI Key: https://evolink.ai/early-access\n\"\"\"\nimport requests\nimport time\nimport os\nimport json\nimport random\n\n# ── Configuration ─────────────────────────────────────────────\nAPI_KEY = os.getenv(\"EVOLINK_API_KEY\", \"sk-your-api-key-here\")\nBASE_URL = \"https://api.evolink.ai/v1\"\nHEADERS = {\n    \"Authorization\": f\"Bearer {API_KEY}\",\n    \"Content-Type\": \"application/json\"\n}\n\n\n# ── Reusable Helpers ──────────────────────────────────────────\ndef wait_for_video(task_id, poll_interval=10, timeout=600):\n    \"\"\"Poll a video generation task until completion.\"\"\"\n    elapsed = 0\n    while elapsed \u003C timeout:\n        response = requests.get(\n            f\"{BASE_URL}/tasks/{task_id}\",\n            headers=HEADERS\n        )\n        response.raise_for_status()\n        task = response.json()\n        status = task[\"status\"]\n        progress = task.get(\"progress\", 0)\n        print(f\"  [{elapsed}s] Status: {status} | Progress: {progress}%\")\n        if status == \"completed\":\n            return task\n        elif status == \"failed\":\n            raise RuntimeError(f\"Task {task_id} failed: {task}\")\n        time.sleep(poll_interval)\n        elapsed += poll_interval\n    raise TimeoutError(f\"Task {task_id} timed out after {timeout}s\")\n\n\ndef download_video(url, filename=\"output.mp4\"):\n    \"\"\"Download a video file from a URL.\"\"\"\n    print(f\"Downloading to {filename}...\")\n    resp = requests.get(url, stream=True)\n    resp.raise_for_status()\n    with open(filename, \"wb\") as f:\n        for chunk in resp.iter_content(chunk_size=8192):\n            f.write(chunk)\n    print(f\"Saved: {filename} ({os.path.getsize(filename) / 1024:.0f} KB)\")\n\n\ndef generate_video_with_retry(payload, max_retries=3):\n    \"\"\"Submit a generation request with retry for transient errors.\"\"\"\n    for attempt in range(max_retries):\n        try:\n            response = requests.post(\n                f\"{BASE_URL}/videos/generations\",\n                headers=HEADERS,\n                json=payload,\n                timeout=30\n            )\n            if response.status_code == 200:\n                return response.json()\n            error = response.json().get(\"error\", {})\n            if response.status_code in (400, 401, 402, 404, 413, 422):\n                raise ValueError(\n                    f\"API error {response.status_code}: \"\n                    f\"{error.get('message', 'Unknown')}\"\n                )\n            if response.status_code in (429, 500, 502, 503):\n                wait = (2 ** attempt) + random.uniform(0, 1)\n                print(f\"  Retry {attempt+1}/{max_retries} after {wait:.1f}s\")\n                time.sleep(wait)\n                continue\n        except requests.exceptions.RequestException:\n            wait = (2 ** attempt) + random.uniform(0, 1)\n            print(f\"  Retry {attempt+1}/{max_retries} after {wait:.1f}s\")\n            time.sleep(wait)\n            continue\n    raise RuntimeError(f\"Failed after {max_retries} retries\")\n\n\ndef validate_payload(payload):\n    \"\"\"Validate generation payload before API call.\"\"\"\n    errors = []\n    if not payload.get(\"model\"):\n        errors.append(\"'model' is required\")\n    if not payload.get(\"prompt\") or not payload[\"prompt\"].strip():\n        errors.append(\"'prompt' is required\")\n    duration = payload.get(\"duration\", 5)\n    if duration \u003C 4 or duration > 15:\n        errors.append(f\"'duration' must be 4-15, got {duration}\")\n    quality = payload.get(\"quality\", \"720p\")\n    if quality not in {\"480p\", \"720p\", \"1080p\"}:\n        errors.append(f\"Invalid quality: {quality}\")\n    if errors:\n        raise ValueError(\"Validation failed:\\n\" + \"\\n\".join(f\"  - {e}\" for e in errors))\n\n\ndef cancel_task(task_id):\n    \"\"\"Cancel a pending or processing task.\"\"\"\n    response = requests.post(\n        f\"{BASE_URL}/tasks/{task_id}/cancel\",\n        headers=HEADERS\n    )\n    if response.status_code == 200:\n        print(f\"Task {task_id} cancelled.\")\n    else:\n        print(f\"Cancel failed: {response.json()}\")\n\n\n# ── Example 1: Text-to-Video ─────────────────────────────────\ndef text_to_video():\n    payload = {\n        \"model\": \"seedance-2.0\",\n        \"prompt\": (\n            \"A golden retriever puppy chases a butterfly through \"\n            \"a sunlit meadow. The camera follows the puppy with a \"\n            \"smooth tracking shot as wildflowers sway in the breeze.\"\n        ),\n        \"duration\": 5,\n        \"quality\": \"720p\",\n        \"aspect_ratio\": \"16:9\",\n        \"generate_audio\": True\n    }\n    validate_payload(payload)\n    task = generate_video_with_retry(payload)\n    print(f\"Task: {task['id']} (ETA: {task['task_info']['estimated_time']}s)\")\n    result = wait_for_video(task[\"id\"])\n    download_video(result[\"results\"][0], \"text_to_video.mp4\")\n\n\n# ── Example 2: Image-to-Video ────────────────────────────────\ndef image_to_video():\n    payload = {\n        \"model\": \"seedance-2.0\",\n        \"prompt\": (\n            \"@Image1 as the first frame. The scene slowly comes \"\n            \"to life — leaves rustle gently, soft light shifts \"\n            \"across the frame.\"\n        ),\n        \"image_urls\": [\"https://example.com/your-image.jpg\"],\n        \"duration\": 5,\n        \"quality\": \"720p\"\n    }\n    validate_payload(payload)\n    task = generate_video_with_retry(payload)\n    print(f\"Task: {task['id']}\")\n    result = wait_for_video(task[\"id\"])\n    download_video(result[\"results\"][0], \"image_to_video.mp4\")\n\n\n# ── Example 3: Vertical Social Media Video ───────────────────\ndef social_media_video():\n    payload = {\n        \"model\": \"seedance-2.0\",\n        \"prompt\": (\n            \"A barista pours latte art in slow motion. \"\n            \"Close-up overhead shot, warm cafe lighting.\"\n        ),\n        \"duration\": 8,\n        \"quality\": \"1080p\",\n        \"aspect_ratio\": \"9:16\",\n        \"generate_audio\": True\n    }\n    validate_payload(payload)\n    task = generate_video_with_retry(payload)\n    print(f\"Task: {task['id']}\")\n    result = wait_for_video(task[\"id\"])\n    download_video(result[\"results\"][0], \"social_video.mp4\")\n\n\nif __name__ == \"__main__\":\n    print(\"=== Text-to-Video ===\")\n    text_to_video()\n    # print(\"\\n=== Image-to-Video ===\")\n    # image_to_video()  # Uncomment and set your image URL\n    # print(\"\\n=== Social Media Video ===\")\n    # social_media_video()\n",[27,9217,9218,9222,9227,9232,9237,9241,9247,9253,9259,9265,9271,9275,9279,9295,9303,9311,9327,9335,9339,9343,9347,9352,9372,9377,9385,9395,9403,9423,9431,9435,9439,9447,9459,9475,9511,9523,9529,9541,9572,9576,9584,9614,9618,9622,9636,9640,9661,9677,9681,9697,9715,9719,9753,9757,9761,9775,9780,9792,9798,9806,9818,9828,9836,9845,9849,9861,9867,9879,9913,9921,9936,9960,9964,9990,10016,10059,10063,10067,10074,10100,10140,10144,10148,10170,10174,10178,10186,10191,10199,10211,10219,10241,10250,10266,10286,10304,10320,10345,10364,10371,10417,10422,10427,10436,10442,10451,10472,10481,10486,10499,10521,10528,10549,10554,10559,10565,10574,10583,10594,10601,10606,10611,10616,10621,10632,10643,10654,10663,10668,10674,10683,10727,10740,10760,10765,10770,10776,10785,10794,10805,10812,10817,10822,10828,10833,10847,10858,10867,10872,10877,10886,10911,10924,10942,10947,10952,10958,10968,10977,10988,10995,11001,11007,11012,11023,11034,11045,11054,11059,11064,11073,11098,11111,11129,11134,11139,11152,11164,11169,11175,11181,11187],{"__ignoreMap":140},[144,9219,9220],{"class":146,"line":147},[144,9221,6703],{"class":158},[144,9223,9224],{"class":146,"line":165},[144,9225,9226],{"class":158},"Seedance 2.0 API Tutorial — Complete Script\n",[144,9228,9229],{"class":146,"line":177},[144,9230,9231],{"class":158},"Docs: https://seedance2api.app/docs/video-generation\n",[144,9233,9234],{"class":146,"line":186},[144,9235,9236],{"class":158},"API Key: https://evolink.ai/early-access\n",[144,9238,9239],{"class":146,"line":372},[144,9240,6703],{"class":158},[144,9242,9243,9245],{"class":146,"line":378},[144,9244,346],{"class":257},[144,9246,327],{"class":261},[144,9248,9249,9251],{"class":146,"line":384},[144,9250,346],{"class":257},[144,9252,355],{"class":261},[144,9254,9255,9257],{"class":146,"line":408},[144,9256,346],{"class":257},[144,9258,362],{"class":261},[144,9260,9261,9263],{"class":146,"line":419},[144,9262,346],{"class":257},[144,9264,369],{"class":261},[144,9266,9267,9269],{"class":146,"line":430},[144,9268,346],{"class":257},[144,9270,5036],{"class":261},[144,9272,9273],{"class":146,"line":454},[144,9274,375],{"emptyLinePlaceholder":57},[144,9276,9277],{"class":146,"line":465},[144,9278,381],{"class":173},[144,9280,9281,9283,9285,9287,9289,9291,9293],{"class":146,"line":599},[144,9282,387],{"class":154},[144,9284,390],{"class":257},[144,9286,393],{"class":261},[144,9288,396],{"class":158},[144,9290,399],{"class":261},[144,9292,402],{"class":158},[144,9294,405],{"class":261},[144,9296,9297,9299,9301],{"class":146,"line":604},[144,9298,411],{"class":154},[144,9300,390],{"class":257},[144,9302,416],{"class":158},[144,9304,9305,9307,9309],{"class":146,"line":610},[144,9306,422],{"class":154},[144,9308,390],{"class":257},[144,9310,427],{"class":261},[144,9312,9313,9315,9317,9319,9321,9323,9325],{"class":146,"line":616},[144,9314,433],{"class":158},[144,9316,436],{"class":261},[144,9318,439],{"class":257},[144,9320,442],{"class":158},[144,9322,445],{"class":154},[144,9324,448],{"class":158},[144,9326,451],{"class":261},[144,9328,9329,9331,9333],{"class":146,"line":622},[144,9330,457],{"class":158},[144,9332,436],{"class":261},[144,9334,462],{"class":158},[144,9336,9337],{"class":146,"line":627},[144,9338,468],{"class":261},[144,9340,9341],{"class":146,"line":638},[144,9342,375],{"emptyLinePlaceholder":57},[144,9344,9345],{"class":146,"line":653},[144,9346,375],{"emptyLinePlaceholder":57},[144,9348,9349],{"class":146,"line":659},[144,9350,9351],{"class":173},"# ── Reusable Helpers ──────────────────────────────────────────\n",[144,9353,9354,9356,9358,9360,9362,9364,9366,9368,9370],{"class":146,"line":670},[144,9355,525],{"class":257},[144,9357,528],{"class":150},[144,9359,531],{"class":261},[144,9361,265],{"class":257},[144,9363,536],{"class":154},[144,9365,539],{"class":261},[144,9367,265],{"class":257},[144,9369,544],{"class":154},[144,9371,547],{"class":261},[144,9373,9374],{"class":146,"line":697},[144,9375,9376],{"class":158},"    \"\"\"Poll a video generation task until completion.\"\"\"\n",[144,9378,9379,9381,9383],{"class":146,"line":709},[144,9380,630],{"class":261},[144,9382,265],{"class":257},[144,9384,635],{"class":154},[144,9386,9387,9389,9391,9393],{"class":146,"line":715},[144,9388,641],{"class":257},[144,9390,644],{"class":261},[144,9392,647],{"class":257},[144,9394,650],{"class":261},[144,9396,9397,9399,9401],{"class":146,"line":721},[144,9398,662],{"class":261},[144,9400,265],{"class":257},[144,9402,667],{"class":261},[144,9404,9405,9407,9409,9411,9413,9415,9417,9419,9421],{"class":146,"line":727},[144,9406,673],{"class":257},[144,9408,448],{"class":158},[144,9410,678],{"class":154},[144,9412,681],{"class":158},[144,9414,684],{"class":154},[144,9416,687],{"class":261},[144,9418,690],{"class":154},[144,9420,448],{"class":158},[144,9422,451],{"class":261},[144,9424,9425,9427,9429],{"class":146,"line":738},[144,9426,701],{"class":700},[144,9428,265],{"class":257},[144,9430,706],{"class":154},[144,9432,9433],{"class":146,"line":743},[144,9434,712],{"class":261},[144,9436,9437],{"class":146,"line":749},[144,9438,724],{"class":261},[144,9440,9441,9443,9445],{"class":146,"line":766},[144,9442,730],{"class":261},[144,9444,265],{"class":257},[144,9446,735],{"class":261},[144,9448,9449,9451,9453,9455,9457],{"class":146,"line":787},[144,9450,752],{"class":261},[144,9452,265],{"class":257},[144,9454,757],{"class":261},[144,9456,760],{"class":158},[144,9458,763],{"class":261},[144,9460,9461,9463,9465,9467,9469,9471,9473],{"class":146,"line":833},[144,9462,769],{"class":261},[144,9464,265],{"class":257},[144,9466,774],{"class":261},[144,9468,777],{"class":158},[144,9470,399],{"class":261},[144,9472,782],{"class":154},[144,9474,405],{"class":261},[144,9476,9477,9479,9481,9483,9485,9487,9489,9491,9493,9495,9497,9499,9501,9503,9505,9507,9509],{"class":146,"line":838},[144,9478,790],{"class":154},[144,9480,793],{"class":261},[144,9482,439],{"class":257},[144,9484,798],{"class":158},[144,9486,684],{"class":154},[144,9488,803],{"class":261},[144,9490,690],{"class":154},[144,9492,808],{"class":158},[144,9494,684],{"class":154},[144,9496,813],{"class":261},[144,9498,690],{"class":154},[144,9500,818],{"class":158},[144,9502,684],{"class":154},[144,9504,823],{"class":261},[144,9506,690],{"class":154},[144,9508,828],{"class":158},[144,9510,405],{"class":261},[144,9512,9513,9515,9517,9519,9521],{"class":146,"line":844},[144,9514,847],{"class":257},[144,9516,850],{"class":261},[144,9518,853],{"class":257},[144,9520,856],{"class":158},[144,9522,859],{"class":261},[144,9524,9525,9527],{"class":146,"line":862},[144,9526,865],{"class":257},[144,9528,868],{"class":261},[144,9530,9531,9533,9535,9537,9539],{"class":146,"line":871},[144,9532,874],{"class":257},[144,9534,850],{"class":261},[144,9536,853],{"class":257},[144,9538,881],{"class":158},[144,9540,859],{"class":261},[144,9542,9543,9545,9547,9549,9551,9553,9555,9557,9559,9561,9563,9566,9568,9570],{"class":146,"line":886},[144,9544,905],{"class":257},[144,9546,908],{"class":154},[144,9548,793],{"class":261},[144,9550,439],{"class":257},[144,9552,920],{"class":158},[144,9554,684],{"class":154},[144,9556,687],{"class":261},[144,9558,690],{"class":154},[144,9560,929],{"class":158},[144,9562,684],{"class":154},[144,9564,9565],{"class":261},"task",[144,9567,690],{"class":154},[144,9569,448],{"class":158},[144,9571,405],{"class":261},[144,9573,9574],{"class":146,"line":902},[144,9575,972],{"class":261},[144,9577,9578,9580,9582],{"class":146,"line":914},[144,9579,978],{"class":261},[144,9581,981],{"class":257},[144,9583,984],{"class":261},[144,9585,9586,9588,9590,9592,9594,9596,9598,9600,9602,9604,9606,9608,9610,9612],{"class":146,"line":952},[144,9587,995],{"class":257},[144,9589,998],{"class":154},[144,9591,793],{"class":261},[144,9593,439],{"class":257},[144,9595,920],{"class":158},[144,9597,684],{"class":154},[144,9599,687],{"class":261},[144,9601,690],{"class":154},[144,9603,1013],{"class":158},[144,9605,684],{"class":154},[144,9607,1018],{"class":261},[144,9609,690],{"class":154},[144,9611,1023],{"class":158},[144,9613,405],{"class":261},[144,9615,9616],{"class":146,"line":958},[144,9617,375],{"emptyLinePlaceholder":57},[144,9619,9620],{"class":146,"line":963},[144,9621,375],{"emptyLinePlaceholder":57},[144,9623,9624,9626,9628,9630,9632,9634],{"class":146,"line":969},[144,9625,525],{"class":257},[144,9627,1081],{"class":150},[144,9629,1084],{"class":261},[144,9631,265],{"class":257},[144,9633,1089],{"class":158},[144,9635,547],{"class":261},[144,9637,9638],{"class":146,"line":975},[144,9639,1096],{"class":158},[144,9641,9642,9644,9646,9648,9651,9653,9655,9657,9659],{"class":146,"line":987},[144,9643,1101],{"class":154},[144,9645,793],{"class":261},[144,9647,439],{"class":257},[144,9649,9650],{"class":158},"\"Downloading to ",[144,9652,684],{"class":154},[144,9654,1113],{"class":261},[144,9656,690],{"class":154},[144,9658,1118],{"class":158},[144,9660,405],{"class":261},[144,9662,9663,9665,9667,9669,9671,9673,9675],{"class":146,"line":992},[144,9664,1125],{"class":261},[144,9666,265],{"class":257},[144,9668,1130],{"class":261},[144,9670,1133],{"class":700},[144,9672,265],{"class":257},[144,9674,1138],{"class":154},[144,9676,405],{"class":261},[144,9678,9679],{"class":146,"line":5530},[144,9680,1145],{"class":261},[144,9682,9683,9685,9687,9689,9691,9693,9695],{"class":146,"line":5539},[144,9684,1150],{"class":257},[144,9686,1153],{"class":154},[144,9688,1156],{"class":261},[144,9690,1159],{"class":158},[144,9692,1162],{"class":261},[144,9694,1165],{"class":257},[144,9696,1168],{"class":261},[144,9698,9699,9701,9703,9705,9707,9709,9711,9713],{"class":146,"line":5545},[144,9700,1173],{"class":257},[144,9702,1176],{"class":261},[144,9704,1179],{"class":257},[144,9706,1182],{"class":261},[144,9708,1185],{"class":700},[144,9710,265],{"class":257},[144,9712,1190],{"class":154},[144,9714,547],{"class":261},[144,9716,9717],{"class":146,"line":5573},[144,9718,1197],{"class":261},[144,9720,9721,9723,9725,9727,9729,9731,9733,9735,9737,9739,9741,9743,9745,9747,9749,9751],{"class":146,"line":5604},[144,9722,1101],{"class":154},[144,9724,793],{"class":261},[144,9726,439],{"class":257},[144,9728,1208],{"class":158},[144,9730,684],{"class":154},[144,9732,1113],{"class":261},[144,9734,690],{"class":154},[144,9736,1217],{"class":158},[144,9738,684],{"class":154},[144,9740,1222],{"class":261},[144,9742,1225],{"class":257},[144,9744,1228],{"class":154},[144,9746,1231],{"class":257},[144,9748,690],{"class":154},[144,9750,1236],{"class":158},[144,9752,405],{"class":261},[144,9754,9755],{"class":146,"line":5624},[144,9756,375],{"emptyLinePlaceholder":57},[144,9758,9759],{"class":146,"line":5630},[144,9760,375],{"emptyLinePlaceholder":57},[144,9762,9763,9765,9767,9769,9771,9773],{"class":146,"line":5636},[144,9764,525],{"class":257},[144,9766,5047],{"class":150},[144,9768,5050],{"class":261},[144,9770,265],{"class":257},[144,9772,5055],{"class":154},[144,9774,547],{"class":261},[144,9776,9777],{"class":146,"line":5641},[144,9778,9779],{"class":158},"    \"\"\"Submit a generation request with retry for transient errors.\"\"\"\n",[144,9781,9782,9784,9786,9788,9790],{"class":146,"line":5654},[144,9783,5118],{"class":257},[144,9785,5121],{"class":261},[144,9787,1179],{"class":257},[144,9789,5126],{"class":154},[144,9791,5129],{"class":261},[144,9793,9794,9796],{"class":146,"line":5660},[144,9795,5134],{"class":257},[144,9797,859],{"class":261},[144,9799,9800,9802,9804],{"class":146,"line":5687},[144,9801,5141],{"class":261},[144,9803,265],{"class":257},[144,9805,1431],{"class":261},[144,9807,9808,9810,9812,9814,9816],{"class":146,"line":5727},[144,9809,917],{"class":257},[144,9811,448],{"class":158},[144,9813,678],{"class":154},[144,9815,1443],{"class":158},[144,9817,451],{"class":261},[144,9819,9820,9822,9824,9826],{"class":146,"line":5746},[144,9821,5162],{"class":700},[144,9823,265],{"class":257},[144,9825,422],{"class":154},[144,9827,451],{"class":261},[144,9829,9830,9832,9834],{"class":146,"line":5751},[144,9831,5173],{"class":700},[144,9833,265],{"class":257},[144,9835,5178],{"class":261},[144,9837,9838,9840,9842],{"class":146,"line":5756},[144,9839,5183],{"class":700},[144,9841,265],{"class":257},[144,9843,9844],{"class":154},"30\n",[144,9846,9847],{"class":146,"line":5761},[144,9848,955],{"class":261},[144,9850,9851,9853,9855,9857,9859],{"class":146,"line":7441},[144,9852,5209],{"class":257},[144,9854,2508],{"class":261},[144,9856,853],{"class":257},[144,9858,2513],{"class":154},[144,9860,859],{"class":261},[144,9862,9863,9865],{"class":146,"line":7447},[144,9864,5222],{"class":257},[144,9866,735],{"class":261},[144,9868,9869,9871,9873,9875,9877],{"class":146,"line":7458},[144,9870,5238],{"class":261},[144,9872,265],{"class":257},[144,9874,5243],{"class":261},[144,9876,896],{"class":158},[144,9878,899],{"class":261},[144,9880,9881,9883,9885,9887,9889,9891,9893,9895,9897,9899,9901,9903,9905,9907,9909,9911],{"class":146,"line":7469},[144,9882,5209],{"class":257},[144,9884,2508],{"class":261},[144,9886,1179],{"class":257},[144,9888,1217],{"class":261},[144,9890,3636],{"class":154},[144,9892,399],{"class":261},[144,9894,4847],{"class":154},[144,9896,399],{"class":261},[144,9898,4865],{"class":154},[144,9900,399],{"class":261},[144,9902,4883],{"class":154},[144,9904,399],{"class":261},[144,9906,4901],{"class":154},[144,9908,399],{"class":261},[144,9910,4919],{"class":154},[144,9912,547],{"class":261},[144,9914,9915,9917,9919],{"class":146,"line":7480},[144,9916,5334],{"class":257},[144,9918,5337],{"class":154},[144,9920,911],{"class":261},[144,9922,9923,9925,9927,9929,9931,9933],{"class":146,"line":7485},[144,9924,5344],{"class":257},[144,9926,5347],{"class":158},[144,9928,684],{"class":154},[144,9930,5352],{"class":261},[144,9932,690],{"class":154},[144,9934,9935],{"class":158},": \"\n",[144,9937,9938,9940,9942,9944,9947,9949,9951,9954,9956,9958],{"class":146,"line":7491},[144,9939,5344],{"class":257},[144,9941,448],{"class":158},[144,9943,684],{"class":154},[144,9945,9946],{"class":261},"error.get(",[144,9948,937],{"class":158},[144,9950,399],{"class":261},[144,9952,9953],{"class":158},"'Unknown'",[144,9955,107],{"class":261},[144,9957,690],{"class":154},[144,9959,949],{"class":158},[144,9961,9962],{"class":146,"line":7499},[144,9963,5370],{"class":261},[144,9965,9966,9968,9970,9972,9974,9976,9978,9980,9982,9984,9986,9988],{"class":146,"line":7513},[144,9967,5209],{"class":257},[144,9969,2508],{"class":261},[144,9971,1179],{"class":257},[144,9973,1217],{"class":261},[144,9975,4937],{"class":154},[144,9977,399],{"class":261},[144,9979,4958],{"class":154},[144,9981,399],{"class":261},[144,9983,4978],{"class":154},[144,9985,399],{"class":261},[144,9987,4998],{"class":154},[144,9989,547],{"class":261},[144,9991,9992,9994,9996,9998,10000,10002,10004,10006,10008,10010,10012,10014],{"class":146,"line":7518},[144,9993,5410],{"class":261},[144,9995,265],{"class":257},[144,9997,1217],{"class":261},[144,9999,5417],{"class":154},[144,10001,5420],{"class":257},[144,10003,5423],{"class":261},[144,10005,5426],{"class":257},[144,10007,5429],{"class":261},[144,10009,782],{"class":154},[144,10011,399],{"class":261},[144,10013,5436],{"class":154},[144,10015,405],{"class":261},[144,10017,10018,10020,10022,10024,10026,10028,10031,10033,10036,10038,10040,10042,10044,10047,10049,10051,10053,10055,10057],{"class":146,"line":7532},[144,10019,5443],{"class":154},[144,10021,793],{"class":261},[144,10023,439],{"class":257},[144,10025,5450],{"class":158},[144,10027,684],{"class":154},[144,10029,10030],{"class":261},"attempt",[144,10032,5426],{"class":257},[144,10034,10035],{"class":154},"1}",[144,10037,1225],{"class":158},[144,10039,684],{"class":154},[144,10041,5467],{"class":261},[144,10043,690],{"class":154},[144,10045,10046],{"class":158}," after ",[144,10048,684],{"class":154},[144,10050,5485],{"class":261},[144,10052,5488],{"class":257},[144,10054,690],{"class":154},[144,10056,1023],{"class":158},[144,10058,405],{"class":261},[144,10060,10061],{"class":146,"line":7546},[144,10062,5518],{"class":261},[144,10064,10065],{"class":146,"line":7578},[144,10066,5523],{"class":257},[144,10068,10069,10071],{"class":146,"line":7590},[144,10070,5533],{"class":257},[144,10072,10073],{"class":261}," requests.exceptions.RequestException:\n",[144,10075,10076,10078,10080,10082,10084,10086,10088,10090,10092,10094,10096,10098],{"class":146,"line":7600},[144,10077,5548],{"class":261},[144,10079,265],{"class":257},[144,10081,1217],{"class":261},[144,10083,5417],{"class":154},[144,10085,5420],{"class":257},[144,10087,5423],{"class":261},[144,10089,5426],{"class":257},[144,10091,5429],{"class":261},[144,10093,782],{"class":154},[144,10095,399],{"class":261},[144,10097,5436],{"class":154},[144,10099,405],{"class":261},[144,10101,10102,10104,10106,10108,10110,10112,10114,10116,10118,10120,10122,10124,10126,10128,10130,10132,10134,10136,10138],{"class":146,"line":7605},[144,10103,5576],{"class":154},[144,10105,793],{"class":261},[144,10107,439],{"class":257},[144,10109,5450],{"class":158},[144,10111,684],{"class":154},[144,10113,10030],{"class":261},[144,10115,5426],{"class":257},[144,10117,10035],{"class":154},[144,10119,1225],{"class":158},[144,10121,684],{"class":154},[144,10123,5467],{"class":261},[144,10125,690],{"class":154},[144,10127,10046],{"class":158},[144,10129,684],{"class":154},[144,10131,5485],{"class":261},[144,10133,5488],{"class":257},[144,10135,690],{"class":154},[144,10137,1023],{"class":158},[144,10139,405],{"class":261},[144,10141,10142],{"class":146,"line":7612},[144,10143,5627],{"class":261},[144,10145,10146],{"class":146,"line":7634},[144,10147,5633],{"class":257},[144,10149,10150,10152,10154,10156,10158,10160,10162,10164,10166,10168],{"class":146,"line":7665},[144,10151,995],{"class":257},[144,10153,908],{"class":154},[144,10155,793],{"class":261},[144,10157,439],{"class":257},[144,10159,5772],{"class":158},[144,10161,684],{"class":154},[144,10163,5467],{"class":261},[144,10165,690],{"class":154},[144,10167,5781],{"class":158},[144,10169,405],{"class":261},[144,10171,10172],{"class":146,"line":7670},[144,10173,375],{"emptyLinePlaceholder":57},[144,10175,10176],{"class":146,"line":7676},[144,10177,375],{"emptyLinePlaceholder":57},[144,10179,10180,10182,10184],{"class":146,"line":7701},[144,10181,525],{"class":257},[144,10183,5844],{"class":150},[144,10185,5847],{"class":261},[144,10187,10188],{"class":146,"line":7706},[144,10189,10190],{"class":158},"    \"\"\"Validate generation payload before API call.\"\"\"\n",[144,10192,10193,10195,10197],{"class":146,"line":7711},[144,10194,5870],{"class":261},[144,10196,265],{"class":257},[144,10198,5875],{"class":261},[144,10200,10201,10203,10205,10207,10209],{"class":146,"line":7734},[144,10202,2505],{"class":257},[144,10204,5891],{"class":257},[144,10206,5894],{"class":261},[144,10208,5897],{"class":158},[144,10210,547],{"class":261},[144,10212,10213,10215,10217],{"class":146,"line":7744},[144,10214,5904],{"class":261},[144,10216,5907],{"class":158},[144,10218,405],{"class":261},[144,10220,10221,10223,10225,10227,10229,10231,10233,10235,10237,10239],{"class":146,"line":7750},[144,10222,2505],{"class":257},[144,10224,5891],{"class":257},[144,10226,5894],{"class":261},[144,10228,5920],{"class":158},[144,10230,1162],{"class":261},[144,10232,5925],{"class":257},[144,10234,5891],{"class":257},[144,10236,5930],{"class":261},[144,10238,5920],{"class":158},[144,10240,5935],{"class":261},[144,10242,10243,10245,10248],{"class":146,"line":7768},[144,10244,5904],{"class":261},[144,10246,10247],{"class":158},"\"'prompt' is required\"",[144,10249,405],{"class":261},[144,10251,10252,10254,10256,10258,10260,10262,10264],{"class":146,"line":7773},[144,10253,5958],{"class":261},[144,10255,265],{"class":257},[144,10257,5894],{"class":261},[144,10259,5965],{"class":158},[144,10261,399],{"class":261},[144,10263,1351],{"class":154},[144,10265,405],{"class":261},[144,10267,10268,10270,10272,10274,10276,10278,10280,10282,10284],{"class":146,"line":7778},[144,10269,2505],{"class":257},[144,10271,5978],{"class":261},[144,10273,647],{"class":257},[144,10275,5983],{"class":154},[144,10277,5986],{"class":257},[144,10279,5978],{"class":261},[144,10281,5991],{"class":257},[144,10283,5994],{"class":154},[144,10285,859],{"class":261},[144,10287,10288,10290,10292,10294,10296,10298,10300,10302],{"class":146,"line":7791},[144,10289,5904],{"class":261},[144,10291,439],{"class":257},[144,10293,6005],{"class":158},[144,10295,684],{"class":154},[144,10297,1773],{"class":261},[144,10299,690],{"class":154},[144,10301,448],{"class":158},[144,10303,405],{"class":261},[144,10305,10306,10308,10310,10312,10314,10316,10318],{"class":146,"line":7805},[144,10307,6051],{"class":261},[144,10309,265],{"class":257},[144,10311,5894],{"class":261},[144,10313,6058],{"class":158},[144,10315,399],{"class":261},[144,10317,1367],{"class":158},[144,10319,405],{"class":261},[144,10321,10322,10324,10326,10328,10330,10332,10334,10336,10338,10340,10342],{"class":146,"line":7832},[144,10323,2505],{"class":257},[144,10325,6071],{"class":261},[144,10327,6074],{"class":257},[144,10329,6077],{"class":257},[144,10331,6034],{"class":261},[144,10333,4012],{"class":158},[144,10335,399],{"class":261},[144,10337,1367],{"class":158},[144,10339,399],{"class":261},[144,10341,3709],{"class":158},[144,10343,10344],{"class":261},"}:\n",[144,10346,10347,10349,10351,10354,10356,10358,10360,10362],{"class":146,"line":7846},[144,10348,5904],{"class":261},[144,10350,439],{"class":257},[144,10352,10353],{"class":158},"\"Invalid quality: ",[144,10355,684],{"class":154},[144,10357,1781],{"class":261},[144,10359,690],{"class":154},[144,10361,448],{"class":158},[144,10363,405],{"class":261},[144,10365,10367,10369],{"class":146,"line":10366},99,[144,10368,2505],{"class":257},[144,10370,6346],{"class":261},[144,10372,10374,10376,10378,10380,10383,10385,10387,10389,10391,10393,10395,10397,10399,10401,10403,10405,10407,10409,10411,10413,10415],{"class":146,"line":10373},100,[144,10375,6351],{"class":257},[144,10377,5337],{"class":154},[144,10379,793],{"class":261},[144,10381,10382],{"class":158},"\"Validation failed:",[144,10384,1669],{"class":154},[144,10386,448],{"class":158},[144,10388,6367],{"class":257},[144,10390,6370],{"class":158},[144,10392,1669],{"class":154},[144,10394,448],{"class":158},[144,10396,6377],{"class":261},[144,10398,439],{"class":257},[144,10400,6382],{"class":158},[144,10402,684],{"class":154},[144,10404,5701],{"class":261},[144,10406,690],{"class":154},[144,10408,448],{"class":158},[144,10410,6393],{"class":257},[144,10412,6396],{"class":261},[144,10414,1179],{"class":257},[144,10416,6401],{"class":261},[144,10418,10420],{"class":146,"line":10419},101,[144,10421,375],{"emptyLinePlaceholder":57},[144,10423,10425],{"class":146,"line":10424},102,[144,10426,375],{"emptyLinePlaceholder":57},[144,10428,10430,10432,10434],{"class":146,"line":10429},103,[144,10431,525],{"class":257},[144,10433,2451],{"class":150},[144,10435,2454],{"class":261},[144,10437,10439],{"class":146,"line":10438},104,[144,10440,10441],{"class":158},"    \"\"\"Cancel a pending or processing task.\"\"\"\n",[144,10443,10445,10447,10449],{"class":146,"line":10444},105,[144,10446,1426],{"class":261},[144,10448,265],{"class":257},[144,10450,1431],{"class":261},[144,10452,10454,10456,10458,10460,10462,10464,10466,10468,10470],{"class":146,"line":10453},106,[144,10455,1436],{"class":257},[144,10457,448],{"class":158},[144,10459,678],{"class":154},[144,10461,681],{"class":158},[144,10463,684],{"class":154},[144,10465,687],{"class":261},[144,10467,690],{"class":154},[144,10469,2486],{"class":158},[144,10471,451],{"class":261},[144,10473,10475,10477,10479],{"class":146,"line":10474},107,[144,10476,1454],{"class":700},[144,10478,265],{"class":257},[144,10480,706],{"class":154},[144,10482,10484],{"class":146,"line":10483},108,[144,10485,1482],{"class":261},[144,10487,10489,10491,10493,10495,10497],{"class":146,"line":10488},109,[144,10490,2505],{"class":257},[144,10492,2508],{"class":261},[144,10494,853],{"class":257},[144,10496,2513],{"class":154},[144,10498,859],{"class":261},[144,10500,10502,10504,10506,10508,10510,10512,10514,10516,10519],{"class":146,"line":10501},110,[144,10503,790],{"class":154},[144,10505,793],{"class":261},[144,10507,439],{"class":257},[144,10509,920],{"class":158},[144,10511,684],{"class":154},[144,10513,687],{"class":261},[144,10515,690],{"class":154},[144,10517,10518],{"class":158}," cancelled.\"",[144,10520,405],{"class":261},[144,10522,10524,10526],{"class":146,"line":10523},111,[144,10525,2541],{"class":257},[144,10527,859],{"class":261},[144,10529,10531,10533,10535,10537,10539,10541,10543,10545,10547],{"class":146,"line":10530},112,[144,10532,790],{"class":154},[144,10534,793],{"class":261},[144,10536,439],{"class":257},[144,10538,2554],{"class":158},[144,10540,684],{"class":154},[144,10542,2559],{"class":261},[144,10544,690],{"class":154},[144,10546,448],{"class":158},[144,10548,405],{"class":261},[144,10550,10552],{"class":146,"line":10551},113,[144,10553,375],{"emptyLinePlaceholder":57},[144,10555,10557],{"class":146,"line":10556},114,[144,10558,375],{"emptyLinePlaceholder":57},[144,10560,10562],{"class":146,"line":10561},115,[144,10563,10564],{"class":173},"# ── Example 1: Text-to-Video ─────────────────────────────────\n",[144,10566,10568,10570,10572],{"class":146,"line":10567},116,[144,10569,525],{"class":257},[144,10571,1285],{"class":150},[144,10573,1288],{"class":261},[144,10575,10577,10579,10581],{"class":146,"line":10576},117,[144,10578,1293],{"class":261},[144,10580,265],{"class":257},[144,10582,427],{"class":261},[144,10584,10586,10588,10590,10592],{"class":146,"line":10585},118,[144,10587,1302],{"class":158},[144,10589,436],{"class":261},[144,10591,1307],{"class":158},[144,10593,451],{"class":261},[144,10595,10597,10599],{"class":146,"line":10596},119,[144,10598,1318],{"class":158},[144,10600,1321],{"class":261},[144,10602,10604],{"class":146,"line":10603},120,[144,10605,1326],{"class":158},[144,10607,10609],{"class":146,"line":10608},121,[144,10610,1331],{"class":158},[144,10612,10614],{"class":146,"line":10613},122,[144,10615,1336],{"class":158},[144,10617,10619],{"class":146,"line":10618},123,[144,10620,1341],{"class":261},[144,10622,10624,10626,10628,10630],{"class":146,"line":10623},124,[144,10625,1346],{"class":158},[144,10627,436],{"class":261},[144,10629,1351],{"class":154},[144,10631,451],{"class":261},[144,10633,10635,10637,10639,10641],{"class":146,"line":10634},125,[144,10636,1362],{"class":158},[144,10638,436],{"class":261},[144,10640,1367],{"class":158},[144,10642,451],{"class":261},[144,10644,10646,10648,10650,10652],{"class":146,"line":10645},126,[144,10647,1378],{"class":158},[144,10649,436],{"class":261},[144,10651,1383],{"class":158},[144,10653,451],{"class":261},[144,10655,10657,10659,10661],{"class":146,"line":10656},127,[144,10658,1394],{"class":158},[144,10660,436],{"class":261},[144,10662,3737],{"class":154},[144,10664,10666],{"class":146,"line":10665},128,[144,10667,1406],{"class":261},[144,10669,10671],{"class":146,"line":10670},129,[144,10672,10673],{"class":261},"    validate_payload(payload)\n",[144,10675,10677,10679,10681],{"class":146,"line":10676},130,[144,10678,1495],{"class":261},[144,10680,265],{"class":257},[144,10682,8532],{"class":261},[144,10684,10686,10688,10690,10692,10695,10697,10699,10701,10703,10705,10708,10710,10712,10714,10716,10718,10720,10722,10725],{"class":146,"line":10685},131,[144,10687,1101],{"class":154},[144,10689,793],{"class":261},[144,10691,439],{"class":257},[144,10693,10694],{"class":158},"\"Task: ",[144,10696,684],{"class":154},[144,10698,1528],{"class":261},[144,10700,1531],{"class":158},[144,10702,1534],{"class":261},[144,10704,690],{"class":154},[144,10706,10707],{"class":158}," (ETA: ",[144,10709,684],{"class":154},[144,10711,1528],{"class":261},[144,10713,1558],{"class":158},[144,10715,1561],{"class":261},[144,10717,1564],{"class":158},[144,10719,1534],{"class":261},[144,10721,690],{"class":154},[144,10723,10724],{"class":158},"s)\"",[144,10726,405],{"class":261},[144,10728,10730,10732,10734,10736,10738],{"class":146,"line":10729},132,[144,10731,1617],{"class":261},[144,10733,265],{"class":257},[144,10735,1622],{"class":261},[144,10737,1625],{"class":158},[144,10739,1628],{"class":261},[144,10741,10743,10746,10748,10750,10752,10755,10758],{"class":146,"line":10742},133,[144,10744,10745],{"class":261},"    download_video(result[",[144,10747,1650],{"class":158},[144,10749,1561],{"class":261},[144,10751,782],{"class":154},[144,10753,10754],{"class":261},"], ",[144,10756,10757],{"class":158},"\"text_to_video.mp4\"",[144,10759,405],{"class":261},[144,10761,10763],{"class":146,"line":10762},134,[144,10764,375],{"emptyLinePlaceholder":57},[144,10766,10768],{"class":146,"line":10767},135,[144,10769,375],{"emptyLinePlaceholder":57},[144,10771,10773],{"class":146,"line":10772},136,[144,10774,10775],{"class":173},"# ── Example 2: Image-to-Video ────────────────────────────────\n",[144,10777,10779,10781,10783],{"class":146,"line":10778},137,[144,10780,525],{"class":257},[144,10782,2637],{"class":150},[144,10784,1288],{"class":261},[144,10786,10788,10790,10792],{"class":146,"line":10787},138,[144,10789,1293],{"class":261},[144,10791,265],{"class":257},[144,10793,427],{"class":261},[144,10795,10797,10799,10801,10803],{"class":146,"line":10796},139,[144,10798,1302],{"class":158},[144,10800,436],{"class":261},[144,10802,1307],{"class":158},[144,10804,451],{"class":261},[144,10806,10808,10810],{"class":146,"line":10807},140,[144,10809,1318],{"class":158},[144,10811,1321],{"class":261},[144,10813,10815],{"class":146,"line":10814},141,[144,10816,2668],{"class":158},[144,10818,10820],{"class":146,"line":10819},142,[144,10821,2673],{"class":158},[144,10823,10825],{"class":146,"line":10824},143,[144,10826,10827],{"class":158},"            \"across the frame.\"\n",[144,10829,10831],{"class":146,"line":10830},144,[144,10832,1341],{"class":261},[144,10834,10836,10838,10841,10844],{"class":146,"line":10835},145,[144,10837,2687],{"class":158},[144,10839,10840],{"class":261},": [",[144,10842,10843],{"class":158},"\"https://example.com/your-image.jpg\"",[144,10845,10846],{"class":261},"],\n",[144,10848,10850,10852,10854,10856],{"class":146,"line":10849},146,[144,10851,1346],{"class":158},[144,10853,436],{"class":261},[144,10855,1351],{"class":154},[144,10857,451],{"class":261},[144,10859,10861,10863,10865],{"class":146,"line":10860},147,[144,10862,1362],{"class":158},[144,10864,436],{"class":261},[144,10866,8511],{"class":158},[144,10868,10870],{"class":146,"line":10869},148,[144,10871,1406],{"class":261},[144,10873,10875],{"class":146,"line":10874},149,[144,10876,10673],{"class":261},[144,10878,10880,10882,10884],{"class":146,"line":10879},150,[144,10881,1495],{"class":261},[144,10883,265],{"class":257},[144,10885,8532],{"class":261},[144,10887,10889,10891,10893,10895,10897,10899,10901,10903,10905,10907,10909],{"class":146,"line":10888},151,[144,10890,1101],{"class":154},[144,10892,793],{"class":261},[144,10894,439],{"class":257},[144,10896,10694],{"class":158},[144,10898,684],{"class":154},[144,10900,1528],{"class":261},[144,10902,1531],{"class":158},[144,10904,1534],{"class":261},[144,10906,690],{"class":154},[144,10908,448],{"class":158},[144,10910,405],{"class":261},[144,10912,10914,10916,10918,10920,10922],{"class":146,"line":10913},152,[144,10915,1617],{"class":261},[144,10917,265],{"class":257},[144,10919,1622],{"class":261},[144,10921,1625],{"class":158},[144,10923,1628],{"class":261},[144,10925,10927,10929,10931,10933,10935,10937,10940],{"class":146,"line":10926},153,[144,10928,10745],{"class":261},[144,10930,1650],{"class":158},[144,10932,1561],{"class":261},[144,10934,782],{"class":154},[144,10936,10754],{"class":261},[144,10938,10939],{"class":158},"\"image_to_video.mp4\"",[144,10941,405],{"class":261},[144,10943,10945],{"class":146,"line":10944},154,[144,10946,375],{"emptyLinePlaceholder":57},[144,10948,10950],{"class":146,"line":10949},155,[144,10951,375],{"emptyLinePlaceholder":57},[144,10953,10955],{"class":146,"line":10954},156,[144,10956,10957],{"class":173},"# ── Example 3: Vertical Social Media Video ───────────────────\n",[144,10959,10961,10963,10966],{"class":146,"line":10960},157,[144,10962,525],{"class":257},[144,10964,10965],{"class":150}," social_media_video",[144,10967,1288],{"class":261},[144,10969,10971,10973,10975],{"class":146,"line":10970},158,[144,10972,1293],{"class":261},[144,10974,265],{"class":257},[144,10976,427],{"class":261},[144,10978,10980,10982,10984,10986],{"class":146,"line":10979},159,[144,10981,1302],{"class":158},[144,10983,436],{"class":261},[144,10985,1307],{"class":158},[144,10987,451],{"class":261},[144,10989,10991,10993],{"class":146,"line":10990},160,[144,10992,1318],{"class":158},[144,10994,1321],{"class":261},[144,10996,10998],{"class":146,"line":10997},161,[144,10999,11000],{"class":158},"            \"A barista pours latte art in slow motion. \"\n",[144,11002,11004],{"class":146,"line":11003},162,[144,11005,11006],{"class":158},"            \"Close-up overhead shot, warm cafe lighting.\"\n",[144,11008,11010],{"class":146,"line":11009},163,[144,11011,1341],{"class":261},[144,11013,11015,11017,11019,11021],{"class":146,"line":11014},164,[144,11016,1346],{"class":158},[144,11018,436],{"class":261},[144,11020,3697],{"class":154},[144,11022,451],{"class":261},[144,11024,11026,11028,11030,11032],{"class":146,"line":11025},165,[144,11027,1362],{"class":158},[144,11029,436],{"class":261},[144,11031,3709],{"class":158},[144,11033,451],{"class":261},[144,11035,11037,11039,11041,11043],{"class":146,"line":11036},166,[144,11038,1378],{"class":158},[144,11040,436],{"class":261},[144,11042,3721],{"class":158},[144,11044,451],{"class":261},[144,11046,11048,11050,11052],{"class":146,"line":11047},167,[144,11049,1394],{"class":158},[144,11051,436],{"class":261},[144,11053,3737],{"class":154},[144,11055,11057],{"class":146,"line":11056},168,[144,11058,1406],{"class":261},[144,11060,11062],{"class":146,"line":11061},169,[144,11063,10673],{"class":261},[144,11065,11067,11069,11071],{"class":146,"line":11066},170,[144,11068,1495],{"class":261},[144,11070,265],{"class":257},[144,11072,8532],{"class":261},[144,11074,11076,11078,11080,11082,11084,11086,11088,11090,11092,11094,11096],{"class":146,"line":11075},171,[144,11077,1101],{"class":154},[144,11079,793],{"class":261},[144,11081,439],{"class":257},[144,11083,10694],{"class":158},[144,11085,684],{"class":154},[144,11087,1528],{"class":261},[144,11089,1531],{"class":158},[144,11091,1534],{"class":261},[144,11093,690],{"class":154},[144,11095,448],{"class":158},[144,11097,405],{"class":261},[144,11099,11101,11103,11105,11107,11109],{"class":146,"line":11100},172,[144,11102,1617],{"class":261},[144,11104,265],{"class":257},[144,11106,1622],{"class":261},[144,11108,1625],{"class":158},[144,11110,1628],{"class":261},[144,11112,11114,11116,11118,11120,11122,11124,11127],{"class":146,"line":11113},173,[144,11115,10745],{"class":261},[144,11117,1650],{"class":158},[144,11119,1561],{"class":261},[144,11121,782],{"class":154},[144,11123,10754],{"class":261},[144,11125,11126],{"class":158},"\"social_video.mp4\"",[144,11128,405],{"class":261},[144,11130,11132],{"class":146,"line":11131},174,[144,11133,375],{"emptyLinePlaceholder":57},[144,11135,11137],{"class":146,"line":11136},175,[144,11138,375],{"emptyLinePlaceholder":57},[144,11140,11142,11144,11146,11148,11150],{"class":146,"line":11141},176,[144,11143,1718],{"class":257},[144,11145,1721],{"class":154},[144,11147,1724],{"class":257},[144,11149,1727],{"class":158},[144,11151,859],{"class":261},[144,11153,11155,11157,11159,11162],{"class":146,"line":11154},177,[144,11156,1101],{"class":154},[144,11158,793],{"class":261},[144,11160,11161],{"class":158},"\"=== Text-to-Video ===\"",[144,11163,405],{"class":261},[144,11165,11167],{"class":146,"line":11166},178,[144,11168,1734],{"class":261},[144,11170,11172],{"class":146,"line":11171},179,[144,11173,11174],{"class":173},"    # print(\"\\n=== Image-to-Video ===\")\n",[144,11176,11178],{"class":146,"line":11177},180,[144,11179,11180],{"class":173},"    # image_to_video()  # Uncomment and set your image URL\n",[144,11182,11184],{"class":146,"line":11183},181,[144,11185,11186],{"class":173},"    # print(\"\\n=== Social Media Video ===\")\n",[144,11188,11190],{"class":146,"line":11189},182,[144,11191,11192],{"class":173},"    # social_media_video()\n",[17,11194,11195],{},[10,11196,11197,11200,11201,6913,11203,11206],{},[22,11198,11199],{},"Tip:"," To test with the currently available model, change ",[27,11202,1307],{},[27,11204,11205],{},"\"seedance-1.5-pro\"",". The API interface is identical — same endpoint, same parameters, same response format. When Seedance 2.0 is fully rolled out, just switch the model name back.",[10,11208,11209],{},[22,11210,11211],{},[36,11212,11214],{"href":38,"rel":11213},[40],"Start building → Get your free API key at EvoLink",[11216,11217,11218],"style",{},"html pre.shiki code .svObZ, html code.shiki .svObZ{--shiki-default:#B392F0}html pre.shiki code .sDLfK, html code.shiki .sDLfK{--shiki-default:#79B8FF}html pre.shiki code .sU2Wk, html code.shiki .sU2Wk{--shiki-default:#9ECBFF}html pre.shiki code .sAwPA, html code.shiki .sAwPA{--shiki-default:#6A737D}html .default .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html .shiki span {color: var(--shiki-default);background: var(--shiki-default-bg);font-style: var(--shiki-default-font-style);font-weight: var(--shiki-default-font-weight);text-decoration: var(--shiki-default-text-decoration);}html pre.shiki code .snl16, html code.shiki .snl16{--shiki-default:#F97583}html pre.shiki code .s95oV, html code.shiki .s95oV{--shiki-default:#E1E4E8}html pre.shiki code .s9osk, html code.shiki .s9osk{--shiki-default:#FFAB70}",{"title":140,"searchDepth":165,"depth":165,"links":11220},[11221,11224,11225,11226,11230,11235,11240,11244,11250,11258,11259,11264,11276],{"id":49,"depth":165,"text":50,"children":11222},[11223],{"id":93,"depth":177,"text":94},{"id":203,"depth":165,"text":204},{"id":309,"depth":165,"text":310},{"id":1264,"depth":165,"text":1265,"children":11227},[11228,11229],{"id":1844,"depth":177,"text":1845},{"id":2171,"depth":177,"text":2172},{"id":2216,"depth":165,"text":2217,"children":11231},[11232,11233,11234],{"id":2266,"depth":177,"text":2267},{"id":2346,"depth":177,"text":2347},{"id":2435,"depth":177,"text":2436},{"id":2601,"depth":165,"text":2602,"children":11236},[11237,11238,11239],{"id":2938,"depth":177,"text":2939},{"id":3215,"depth":177,"text":3216},{"id":3291,"depth":177,"text":3292},{"id":3386,"depth":165,"text":3387,"children":11241},[11242,11243],{"id":3640,"depth":177,"text":3641},{"id":4049,"depth":177,"text":4050},{"id":4160,"depth":165,"text":4161,"children":11245},[11246,11247,11248,11249],{"id":4167,"depth":177,"text":4168},{"id":4802,"depth":177,"text":4803},{"id":5016,"depth":177,"text":5017},{"id":5828,"depth":177,"text":5829},{"id":6428,"depth":165,"text":6429,"children":11251},[11252,11253,11254,11255,11256,11257],{"id":6439,"depth":177,"text":6440},{"id":6618,"depth":177,"text":6619},{"id":6684,"depth":177,"text":6685},{"id":7938,"depth":177,"text":7939},{"id":8076,"depth":177,"text":8077},{"id":8255,"depth":177,"text":8256},{"id":8348,"depth":165,"text":8349},{"id":8935,"depth":165,"text":8936,"children":11260},[11261,11262,11263],{"id":8942,"depth":177,"text":8943},{"id":8986,"depth":177,"text":8987},{"id":9012,"depth":177,"text":9013},{"id":9063,"depth":165,"text":9064,"children":11265},[11266,11267,11268,11269,11270,11271,11272,11273,11274,11275],{"id":9067,"depth":177,"text":9068},{"id":9077,"depth":177,"text":9078},{"id":9087,"depth":177,"text":9088},{"id":9097,"depth":177,"text":9098},{"id":9112,"depth":177,"text":9113},{"id":9130,"depth":177,"text":9131},{"id":9144,"depth":177,"text":9145},{"id":9163,"depth":177,"text":9164},{"id":9174,"depth":177,"text":9175},{"id":9194,"depth":177,"text":9195},{"id":9208,"depth":165,"text":9209},"Generate your first AI video with Seedance 2.0 API in Python. Step-by-step tutorial: text-to-video, image-to-video, async polling, webhooks, and error handling.","md",{"date":11280,"image":11281,"seoTitle":11282,"author":11283},"2026-02-27","/s2-hero-api-tutorial.webp","Seedance 2.0 API Tutorial: First AI Video in Python (2026)","J @ EvoLink","/en/blog/seedance-2-api-tutorial-python",{"title":5,"description":11277},"en/blog/seedance-2-api-tutorial-python","-ZlzP0MIl__0Rhg_KNb0Y6rKWGqSG1ray6IAZgQ8Aqk",1775067578224]