वीडियो API: लागत, जनरेशन, स्थिति और डाउनलोड
BetterToken API Key और फिर से चलाए जा सकने वाले Python उदाहरण से दस मॉडलों की लागत, एसिंक्रोनस जनरेशन, स्थिति और MP4 डाउनलोड संभालें।
वीडियो जनरेशन एसिंक्रोनस है। पहले मॉडल की क्षमताएँ देखें और लागत का अनुमान लें। फिर टास्क बनाएं, ID सेव करें, स्थिति देखें और वीडियो तैयार होने पर डाउनलोड करें।
कनेक्शन
| सेटिंग | मान |
|---|---|
| Base URL | https://bettertoken.ai/v1 |
| प्रमाणीकरण | Authorization: Bearer YOUR_API_KEY |
| उपलब्ध मॉडल देखें | GET /v1/video-models |
| जनरेशन से पहले लागत देखें | POST /v1/videos/quote |
| टास्क बनाएं | POST /v1/videos |
| टास्क की स्थिति देखें | GET /v1/videos/{id} |
| वीडियो डाउनलोड करें | GET /v1/videos/{id}/content |
| संगत निर्माण एंडपॉइंट | POST /v1/video/generations |
उपलब्ध मॉडल देखें
export BETTERTOKEN_API_KEY="YOUR_API_KEY"
curl --fail-with-body "https://bettertoken.ai/v1/video-models" \ -H "Authorization: Bearer $BETTERTOKEN_API_KEY"कैटलॉग की हर एंट्री id और operation के संयोजन से पहचानी जाती है। उसके fields, media_limits और constraints का पालन करें। सभी ऑपरेशनों पर एक जैसे पैरामीटर लागू न करें।
हर मॉडल परिवार की शुरुआती सेटिंग
| परिवार | उदाहरण की सेटिंग |
|---|---|
| Seedance CN | 5 सेकंड, 720p, 16:9, ऑडियो बंद |
| Kling 3.0 | 5 सेकंड, 16:9, मानक मोड; सामान्य रिज़ॉल्यूशन फ़ील्ड नहीं |
| MiniMax H3 | 5 सेकंड, 768p, 16:9; मॉडल का डिफ़ॉल्ट ऑडियो |
| Wan 3.0 / Prime | 5 सेकंड, 720p, 16:9, ऑडियो बंद |
| Wan 2.7 T2V / I2V | टेक्स्ट: 5 सेकंड, 720p, 16:9; इमेज: 5 सेकंड, 720p, अनुपात इनपुट के अनुसार |
ये स्क्रिप्ट के शुरुआती संयोजन हैं, हर मॉडल की पूरी सीमाएँ नहीं। परिवार बदलने पर केवल मॉडल का नाम बदलना पर्याप्त नहीं हो सकता। दस सटीक ID और ऑपरेशन यहाँ देखें: मॉडल सूची.
पूरा Python वर्कफ़्लो
Python 3 इस्तेमाल करें। अतिरिक्त डिपेंडेंसी की ज़रूरत नहीं है। एनवायरनमेंट वेरिएबल सेट करें, कोड को video_example.py में सेव करके चलाएं। अनुमान लेने से जनरेशन शुरू नहीं होता। GENERATE लिखने पर असली टास्क बनता है और शुल्क लग सकता है।
export BETTERTOKEN_API_KEY="YOUR_API_KEY"export VIDEO_MODEL="wan-2.7-t2v"export VIDEO_STATE_FILE="video-state.json"python3 video_example.pyनए टास्क के लिए नया VIDEO_STATE_FILE इस्तेमाल करें। उसी टास्क को दोहराते समय अनुरोध, BetterToken API Key और स्टेट फ़ाइल बनाए रखें। स्क्रिप्ट Idempotency-Key या सेव की गई टास्क ID दोबारा इस्तेमाल करती है। प्रतीक्षा सीमा क्लाइंट की सेटिंग है, जनरेशन अवधि की गारंटी नहीं।
import hashlibimport jsonimport osimport shutilimport timeimport uuidfrom pathlib import Pathfrom urllib.error import HTTPErrorfrom urllib.request import Request, urlopen
base_url = "https://bettertoken.ai/v1"api_key = os.environ["BETTERTOKEN_API_KEY"]model = os.getenv("VIDEO_MODEL", "wan-2.7-t2v")state_path = Path(os.getenv("VIDEO_STATE_FILE", "video-state.json"))sample_image = "https://docs.bettertoken.ai/images/nano-banana-guide/sample-07.png"
body = { "model": "wan-2.7-t2v", "operation": "text_to_video", "prompt": "A blue ceramic mug on a white studio table. The camera slowly moves closer. Soft daylight.", "duration": { "mode": "fixed", "seconds": 5 }, "output": { "resolution": "720p", "aspect_ratio": "16:9", "format": "mp4" }}seedance_models = { "seedance-2.5-cn", "seedance-2.0-cn", "seedance-2.0-fast-cn", "seedance-2.0-mini-cn",}allowed_models = seedance_models | { "kling-3.0", "minimax-h3", "wan-3.0", "wan-3.0-prime", "wan-2.7-t2v", "wan-2.7-i2v",}if model not in allowed_models: raise ValueError("Choose a Model ID from the documented batch")body["model"] = modelif model in seedance_models or model in {"wan-3.0", "wan-3.0-prime"}: body["audio"] = {"mode": "off"}elif model == "kling-3.0": body["output"].pop("resolution") body["audio"] = {"mode": "off"} body["provider_options"] = {"kling": {"mode": "std"}}elif model == "minimax-h3": body["output"]["resolution"] = "768p"elif model == "wan-2.7-i2v": body["operation"] = "image_to_video" body["prompt"] = "The camera slowly moves around the blue mug. Preserve its shape and the background." body["output"].pop("aspect_ratio") body["media"] = [{ "id": "first-frame", "type": "image", "role": "first_frame", "source": os.getenv("VIDEO_IMAGE_URL", sample_image), }]
request_file = os.getenv("VIDEO_REQUEST_FILE")if request_file: body = json.loads(Path(request_file).read_text(encoding="utf-8"))
def api(method, path, payload=None, extra_headers=None): headers = {"Authorization": f"Bearer {api_key}"} headers.update(extra_headers or {}) data = None if payload is not None: data = json.dumps(payload).encode("utf-8") headers["Content-Type"] = "application/json" request = Request(base_url + path, data=data, headers=headers, method=method) try: with urlopen(request, timeout=60) as response: return json.load(response) except HTTPError as error: message = error.read().decode("utf-8", errors="replace") raise RuntimeError(f"HTTP {error.code}: {message}") from error
digest = hashlib.sha256(json.dumps(body, sort_keys=True).encode("utf-8")).hexdigest()if state_path.exists(): state = json.loads(state_path.read_text(encoding="utf-8")) if state["request_sha256"] != digest: raise ValueError("Request changed. Use a new VIDEO_STATE_FILE for a new task")else: state = {"request_sha256": digest, "idempotency_key": str(uuid.uuid4())} state_path.write_text(json.dumps(state), encoding="utf-8")
task_id = state.get("task_id")if not task_id: if not state.get("create_attempted"): catalogue = api("GET", "/video-models") if not any(row["id"] == body["model"] and row["operation"] == body["operation"] for row in catalogue["data"]): raise RuntimeError("This model and operation are not in the current catalogue") quote = api("POST", "/videos/quote", body) print(json.dumps(quote, ensure_ascii=False, indent=2)) if input("Review the quote. Type GENERATE to create a paid task: ") != "GENERATE": raise SystemExit("No generation request sent") if time.time() >= quote["expires_at"]: raise RuntimeError("Quote expired. Re-run to request a new quote") state["create_attempted"] = True state_path.write_text(json.dumps(state), encoding="utf-8") task = api("POST", "/videos", body, {"Idempotency-Key": state["idempotency_key"]}) task_id = task["id"] state["task_id"] = task_id state_path.write_text(json.dumps(state), encoding="utf-8")
print("Task ID:", task_id)deadline = time.monotonic() + 1800while time.monotonic() < deadline: task = api("GET", f"/videos/{task_id}") print(task["status"], task["stage"], task["delivery_status"], task["financial_status"]) if task["status"] in {"failed", "canceled"}: raise RuntimeError(json.dumps(task.get("error"), ensure_ascii=False)) if task["delivery_status"] in {"expired", "unavailable"}: raise RuntimeError("Video download is no longer available") if task["status"] == "completed" and task["delivery_status"] == "ready": print(json.dumps(task["billing"], ensure_ascii=False, indent=2)) break time.sleep(5)else: raise TimeoutError("Task still pending. Re-run with the same state file to resume")
request = Request(base_url + f"/videos/{task_id}/content", headers={"Authorization": f"Bearer {api_key}"})with urlopen(request, timeout=120) as response: if response.headers.get_content_type() != "video/mp4": raise RuntimeError("Expected an MP4 response; inspect the task before retrying") with Path("video.mp4").open("wb") as output: shutil.copyfileobj(response, output)print("Saved video.mp4")इमेज से वीडियो
VIDEO_MODEL को wan-2.7-i2v पर सेट करने से नीचे की सार्वजनिक इमेज इस्तेमाल होगी। VIDEO_IMAGE_URL से अपनी अधिकृत HTTPS इमेज दें जिसे सर्वर एक्सेस कर सके। इस एंडपॉइंट पर output.aspect_ratio न भेजें।

{ "model": "wan-2.7-i2v", "operation": "image_to_video", "prompt": "The camera slowly moves around the blue mug. Preserve the mug shape and the white background.", "duration": { "mode": "fixed", "seconds": 5 }, "output": { "resolution": "720p", "format": "mp4" }, "media": [ { "id": "first-frame", "type": "image", "role": "first_frame", "source": "https://docs.bettertoken.ai/images/nano-banana-guide/sample-07.png" } ]}रेफ़रेंस और कस्टम अनुरोध
नीचे का JSON request.json में सेव करें, VIDEO_REQUEST_FILE=request.json सेट करें और नए टास्क के लिए नई स्टेट फ़ाइल इस्तेमाल करें। स्क्रिप्ट उसी अनुरोध की लागत, पुष्टि, सबमिशन, स्थिति और डाउनलोड संभालती है। मीडिया मॉडल के प्रकार और आकार की शर्तों के अनुसार होना चाहिए।
{ "model": "seedance-2.5-cn", "operation": "reference_to_video", "prompt": "Create a studio product video of the blue mug in the reference image. Keep the mug design consistent.", "duration": { "mode": "fixed", "seconds": 5 }, "output": { "resolution": "720p", "aspect_ratio": "16:9", "format": "mp4" }, "audio": { "mode": "off" }, "media": [ { "id": "reference-1", "type": "image", "role": "reference_image", "source": "https://docs.bettertoken.ai/images/nano-banana-guide/sample-07.png" } ]}H3 नतीजा दोबारा बनाएं
प्लेसहोल्डर को अपनी पूरी हो चुकी 768p H3 टास्क ID से बदलें। मूल वीडियो अभी डाउनलोड योग्य और रीजनरेशन के लिए उपयुक्त होना चाहिए। ऊपर के कस्टम वर्कफ़्लो से यह नया सशुल्क टास्क बनेगा। नया प्रॉम्प्ट, अवधि, आउटपुट सेटिंग या मीडिया न जोड़ें। सर्वर मूल टास्क इस्तेमाल करके शर्तें जाँचता है।
{ "model": "minimax-h3", "operation": "video_edit", "provider_options": { "hailuo": { "source_task_id": "YOUR_COMPLETED_H3_TASK_ID" } }}टास्क पूरा होने की पहचान
| फ़ील्ड या स्थिति | कार्रवाई |
|---|---|
202 | केवल स्वीकार हुआ है; वीडियो अभी पूरा नहीं हुआ |
queued / in_progress | कतार में या चल रहा है; स्थिति देखते रहें |
completed + delivery_status: ready | डाउनलोड के लिए तैयार |
failed / canceled | स्थिति देखना रोकें और त्रुटि पढ़ें; नया टास्क अपने-आप न बनाएं |
delivery_status: expired / unavailable | इस टास्क का वीडियो डाउनलोड नहीं हो सकता |
financial_status | बिलिंग जनरेशन और डाउनलोड से अलग है; पुष्टि की प्रतीक्षा करें |
अनुमान और सेटलमेंट पढ़ें
currency अनुमान की मुद्रा है। इसे जनरेशन JSON में न भेजें। reserved_amount आरक्षित राशि और max_charge_amount अनुमान की ऊपरी सीमा है। टास्क बनाते समय लागत फिर से गणना करके तय होती है। सेटलमेंट के लिए billing.currency, billing.net_amount और financial_status देखें। रकम दशमलव स्ट्रिंग होती है। गायब या null मान का अर्थ मुफ़्त नहीं है। मौजूदा कीमतें यहाँ देखें: मौजूदा मॉडल और कीमतें.
आम त्रुटियाँ
| स्थिति | अगला कदम |
|---|---|
401 | API Key जाँचें; उसे JSON या सार्वजनिक लॉग में न रखें |
409 | मूल इडेम्पोटेंसी की और अनुरोध बनाए रखें; पहले ज्ञात टास्क ID देखें |
422 | त्रुटि में दिए फ़ील्ड पथ और मानों के अनुसार सुधारें |
410 | वीडियो की अवधि समाप्त है; अगले नतीजे समय रहते डाउनलोड करें |
429 / 503 / timeout | पहले मौजूदा टास्क देखें; अनिश्चित सबमिशन में मूल की दोबारा इस्तेमाल करें, नई की अपने-आप न बनाएं |

