HappyHorse result links expire in 24 hours: save the file the same day
Alibaba's HappyHorse API says video URLs and task ids last 24 hours. Download on completion, in Python, from Sume's content endpoint or any vendor's.

Alibaba's HappyHorse text-to-video API reference says generated video URLs expire after 24 hours and task ids stay valid for 24 hours, and that tasks usually take 1 to 5 minutes. So the safe pattern is to download the file as soon as the task succeeds and store it yourself.
The same habit is cheap on Sume. A completed /v1/videos job exposes unsigned_urls, and GET /v1/videos/{jobId}/content returns the file with your API key. Sources, read 2026-10-07: Alibaba's reference and Sume's video docs.
What the Alibaba page states
| Item | Statement |
|---|---|
| Model id | happyhorse-1.1-t2v |
| Resolutions | 480P, 720P, 1080P (default) |
| Processing | Asynchronous: create a task, then poll |
| Typical time | 1 to 5 minutes |
| Result URL | Expires after 24 hours |
| Task id | Valid for 24 hours |
| Prompt | Up to 5,000 non-Chinese characters |
Download on completion
This Python polls a Sume job and writes the file to disk the moment it completes. The same shape works for any vendor that gives you a temporary URL.
import os, time, requests
BASE = "https://api.sume.com"
H = {"Authorization": f"Bearer {os.environ['SUME_API_KEY']}"}
def save(job_id, path):
while True:
s = requests.get(f"{BASE}/v1/videos/{job_id}", headers=H, timeout=30).json()
if s["status"] == "completed":
r = requests.get(f"{BASE}/v1/videos/{job_id}/content?index=0",
headers=H, timeout=120)
r.raise_for_status()
with open(path, "wb") as f:
f.write(r.content)
return path
if s["status"] in ("failed", "cancelled"):
raise RuntimeError(s.get("error", "job did not complete"))
time.sleep(30)
if __name__ == "__main__":
print(save(os.environ["JOB_ID"], "clip.mp4"))Habits that avoid a lost render
- Record the job id before you start polling, so a crashed worker can resume.
- Poll every 30 seconds or so, as the docs suggest, not every second.
- Copy the file to your own storage in the same step as the status check.
- Log the vendor, model id and task id next to the stored file, not the temporary URL.
A note on HappyHorse and Sume
Sume's catalog does not list a HappyHorse id, so this page is about the Alibaba constraint and a portable habit, not a route to the model through Sume.
Planning around the one-to-five-minute run
Because tasks usually take 1 to 5 minutes, a worker that polls every few seconds will make dozens of calls per task. Poll at a moderate interval, or use a webhook where the vendor offers one, and give each task a timeout well inside the 24-hour window. A batch that you start at the end of the day should still finish and be downloaded the same evening, so schedule the download job as part of the batch, not as a chore for tomorrow. If a task fails, record the failure with the id, then decide whether to render again.
Schedule the download with the batch
Because tasks usually take 1 to 5 minutes, poll at a moderate interval rather than every few seconds. Store the file, not the vendor link, and log the task id and storage path next to it. If a download fails, retry within the 24-hour window; after that the only remedy is to render again.
Sources
Related posts
More in Developers
- Hindi speech to text API: Sume STT with language_code hi
Transcribe Hindi audio with Sume STT: send language_code hi, check the reported language, and review code-mixed speech. $0.01 per audio minute.
- A 3-minute Timeline render: poll job status, don't sleep a fixed time
Timeline renders are async by default. Submit with an Idempotency-Key, poll /v1/jobs/:id/status until terminal, then read /result. Cost: 3 minutes is $0.30.
- How many new Sume jobs can I submit now? Read generation_limits
Open slots are concurrency_limit minus active and queued jobs, capped by queue_capacity_remaining. A short Python function computes it from a submit response.
- Map a Sume API HTTP status to the next step: one Python function
One Python function turns a Sume status, error code and headers into the next action: wait, retry with the same key, fix the request, or stop. Tested.
Written by Sume