Skip to main content

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 queuedprocessingcompleted (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

ParameterTypeDefaultNotes
modelstringRequired. "ecolink-video-gen-2.0"
promptstringRequired, even when you supply reference media
resolutionstring"720p""480p", "720p", "1080p", "4k" — sets the pricing band
durationinteger5Seconds, 415. Values outside that range are clamped, not rejected
aspect_ratiostring"adaptive""16:9", "4:3", "1:1", "3:4", "9:16", "21:9", "adaptive"
generate_audiobooleantrueAudio 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:

ParameterTypeNotes
reference_imagesobject[]Up to 9 { "url": ..., "role": ... } entries — the role decides the generation mode
reference_image_urlsstring[]Shorthand for a list of reference images with no roles
reference_video_urlstringA reference video (this selects the "with video input" pricing tier)
reference_audio_urlstringA reference audio track

The role on each image chooses what kind of job this is:

RoleResult
first_frameThe video opens on that image
first_frame + last_frameBoth 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 get 429 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:

  1. Resolution band — 480/720p, 1080p, or 4K.
  2. 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.