Video generation
Generate videos with ecolink-video-gen-2.0 via POST /v1/video/generations. Unlike the other endpoints, video is asynchronous — the initial request returns a job ID; you poll until the video is ready. Video is billed on real usage per completed job (see Billing).
Submit a job
curl https://api.ecohash.com/v1/video/generations \
-H "Authorization: Bearer eco_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "ecolink-video-gen-2.0",
"prompt": "a red balloon floating over a mountain at dawn",
"resolution": "720p",
"duration": 5,
"aspect_ratio": "16:9"
}'
Response (202 Accepted):
{
"id": "b3f1c2a4-...",
"status": "processing",
"model": "ecolink-video-gen-2.0"
}
Poll for completion
curl https://api.ecohash.com/v1/video/jobs/b3f1c2a4-... \
-H "Authorization: Bearer eco_YOUR_KEY"
Status progresses queued → processing → completed (or failed). When completed, the response includes a url and a settled billing block:
{
"id": "b3f1c2a4-...",
"status": "completed",
"model": "ecolink-video-gen-2.0",
"prompt": "a red balloon floating over a mountain at dawn",
"width": 1280,
"height": 720,
"created_at": "2026-07-14T09:00:00Z",
"completed_at": "2026-07-14T09:01:12Z",
"url": "https://.../b3f1c2a4.mp4",
"billing": {
"charge_usd": 0.42,
"pricing_tier": "480_720_no_video",
"resolution": "720p",
"duration_seconds": 5,
"billable_tokens": 100000,
"usage_source": "upstream_reported"
}
}
The url is valid for 30 minutes — download and persist the bytes if you need them longer. Polling the job again issues a fresh link. If the job fails, status is "failed" and error carries a safe, actionable message.
Parameters
| Parameter | Type | Default | Notes |
|---|---|---|---|
model | string | — | Required. "ecolink-video-gen-2.0" |
prompt | string | — | Required, even when you supply reference media |
resolution | string | "720p" | "480p", "720p", "1080p", "4k" — sets the pricing band |
duration | integer | 5 | Seconds, 4–15. Values outside that range are clamped, not rejected |
aspect_ratio | string | "adaptive" | "16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive" |
generate_audio | boolean | true | Audio is on unless you set this to false |
Several fields in the shared video request shape are accepted but have no effect
on this model — seed, width, height, and num_inference_steps are
ignored, and num_frames/fps only serve to derive duration when you omit
it. The API reference
lists each one.
Reference inputs
You can condition generation on media you supply, via publicly downloadable URLs:
| Parameter | Type | Notes |
|---|---|---|
reference_images | object[] | Up to 9 { "url": ..., "role": ... } entries — the role decides the generation mode |
reference_image_urls | string[] | Shorthand for a list of reference images with no roles |
reference_video_url | string | A reference video (this selects the "with video input" pricing tier) |
reference_audio_url | string | A reference audio track |
The role on each image chooses what kind of job this is:
| Role | Result |
|---|---|
first_frame | The video opens on that image |
first_frame + last_frame | Both ends pinned; the model generates the transition |
reference_image (or no role) | Guides style and subject without pinning any frame |
Pin the opening frame like this:
"reference_images": [
{ "url": "https://example.com/harbour.jpg", "role": "first_frame" }
]
These are separate modes and cannot be mixed — a request combining
reference_image with a frame role, or frame roles with a reference video, is
rejected with 400 before anything is charged. Full rules, media format limits
and per-mode examples are in the
API reference.
Reference URLs must point to a valid, publicly downloadable media file — if it can't be fetched, the request fails with a message asking you to re-upload.
Estimate cost before submitting
POST /v1/video/quote returns the pricing tier and an estimated token/cost range for the parameters you plan to use, so you can show cost before committing:
curl https://api.ecohash.com/v1/video/quote \
-H "Authorization: Bearer eco_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{ "model": "ecolink-video-gen-2.0", "resolution": "720p", "duration": 5 }'
{
"pricing_tier": "480_720_no_video",
"unit_price_per_1m_tokens": 4.2,
"estimated_tokens_min": 85000,
"estimated_tokens_max": 115000,
"estimated_cost_min_usd": 0.357,
"estimated_cost_max_usd": 0.483,
"currency": "USD",
"note": "Final charge is based on actual tokens reported by the provider."
}
Python
import time, requests
API = "https://api.ecohash.com"
HEADERS = {"Authorization": "Bearer eco_..."}
job = requests.post(f"{API}/v1/video/generations", headers=HEADERS, json={
"model": "ecolink-video-gen-2.0",
"prompt": "a paper airplane gliding through a library",
"resolution": "720p",
"duration": 5,
}).json()
while True:
time.sleep(10)
job = requests.get(f"{API}/v1/video/jobs/{job['id']}", headers=HEADERS).json()
print(job["status"])
if job["status"] in ("completed", "failed"):
break
if job["status"] == "completed":
open("out.mp4", "wb").write(requests.get(job["url"]).content)
Limits
- 10 submissions per 60 seconds per account for
ecolink-video-gen-2.0; over it you get429 Too Many Requests— wait and retry. - Failed submissions do not count toward that limit, so a rejected request can be retried straight away.
Billing
Video is usage-based: the final charge is the real token count the provider reports for the completed job, priced at a rate that depends on two things:
- Resolution band — 480/720p, 1080p, or 4K.
- Whether you supplied a reference video — "with video input" is a distinct rate.
Because the charge settles on actual usage, the pre-submit quote is an estimate range, and the completed job's billing.charge_usd is the authoritative amount. You're only charged for jobs that complete successfully; failed jobs aren't billed. The settled breakdown (tier, resolution, duration, billable tokens) appears in the job's billing block and in Balance & transactions.