API reference
Read a generation’s status, its video link and what it charged.
GET https://loopling.ai/v1/video/generations/{id}
string · required
Your API key, as Bearer lpl_….
idstring · required
The generation’s id. Another account’s ID answers 404.
idstring
Generation ID, vgen_….
objectenum<string>
Object type.
Available options: video.generation
statusenum<string>
succeeded and failed are final.
Available options: queued, running, succeeded, failed
progressinteger
0–100 while queued or running, when reported.
modelstring
The model ID.
created_atstring<date-time>
When it was submitted.
completed_atstring<date-time>
When it reached succeeded or failed.
videoobject
The clip. On succeeded, until the result expires.
urlstring<uri>
Signed MP4 link. Needs no key; works until expires_at.
expires_atstring<date-time>
When url stops working. Read the generation again for a fresh link.
content_typestring
Always video/mp4.
duration_secondsnumber
Seconds billed: the reported length, never more than requested, or the requested length when none is reported.
resolutionstring
The requested resolution, or the default.
aspect_ratiostring
The requested aspect ratio, or the default. adaptive comes back as adaptive.
size_bytesinteger
File size in bytes.
result_expiredboolean
true once the clip is past retention. The record stays.
seedinteger
The seed used, when reported.
ink_reservedinteger
Ink held at submit: the most this generation can cost.
usd_payg_reservednumber
ink_reserved in pay-as-you-go USD.
ink_chargedinteger
Ink charged, once final. 0 when failed.
usd_payg_chargednumber
ink_charged in pay-as-you-go USD.
requestobject
The request as accepted: defaults filled in, metadata inside.
errorobject
Why it failed. On failed only.
codestring
The reason, such as provider_failed, timeout, result_persistence_failed, admission_failed or provider_rejected.
messagestring
A sentence for your logs.
curl
curl https://loopling.ai/v1/video/generations/vgen_01J9X6K3M8Q2 \
-H "Authorization: Bearer $LOOPLING_API_KEY"Node
const res = await fetch('https://loopling.ai/v1/video/generations/vgen_01J9X6K3M8Q2', {
headers: { Authorization: `Bearer ${process.env.LOOPLING_API_KEY}` },
})
const generation = await res.json() // { status: 'running' | 'succeeded' | …, video?, … }Python
import os, requests
res = requests.get(
"https://loopling.ai/v1/video/generations/vgen_01J9X6K3M8Q2",
headers={"Authorization": f"Bearer {os.environ['LOOPLING_API_KEY']}"},
)
generation = res.json() # {"status": "running" | "succeeded" | …, "video": …}{
"id": "vgen_01J9X6K3M8Q2",
"object": "video.generation",
"status": "running",
"progress": 40,
"model": "seedance-2.5",
"created_at": "2026-10-04T08:12:44Z",
"ink_reserved": 320,
"usd_payg_reserved": 3.2,
"request": {
"model": "seedance-2.5",
"prompt": "A paper lantern drifting over a night harbour, slow dolly in",
"aspect_ratio": "16:9",
"resolution": "1080p",
"duration": 5,
"generate_audio": true
}
}{
"id": "vgen_01J9X6K3M8Q2",
"object": "video.generation",
"status": "succeeded",
"model": "seedance-2.5",
"created_at": "2026-10-04T08:12:44Z",
"completed_at": "2026-10-04T08:15:02Z",
"video": {
"url": "https://media.loopling.ai/…?sig=…",
"expires_at": "2026-10-04T08:30:02Z",
"content_type": "video/mp4",
"duration_seconds": 5,
"resolution": "1080p",
"aspect_ratio": "16:9",
"size_bytes": 8421376
},
"ink_reserved": 320,
"usd_payg_reserved": 3.2,
"ink_charged": 320,
"usd_payg_charged": 3.2,
"request": {
"model": "seedance-2.5",
"prompt": "A paper lantern drifting over a night harbour, slow dolly in",
"aspect_ratio": "16:9",
"resolution": "1080p",
"duration": 5,
"generate_audio": true
}
}{
"id": "vgen_01J9X6K3M8Q2",
"object": "video.generation",
"status": "failed",
"model": "seedance-2.5",
"created_at": "2026-10-04T08:12:44Z",
"completed_at": "2026-10-04T08:13:10Z",
"ink_reserved": 320,
"usd_payg_reserved": 3.2,
"ink_charged": 0,
"usd_payg_charged": 0,
"request": {
"model": "seedance-2.5",
"prompt": "A paper lantern drifting over a night harbour, slow dolly in",
"aspect_ratio": "16:9",
"resolution": "1080p",
"duration": 5,
"generate_audio": true
},
"error": {
"code": "provider_failed",
"message": "The render did not complete."
}
}{
"error": {
"type": "not_found_error",
"code": "generation_not_found",
"message": "No video generation with that id.",
"request_id": "0b7c6f1e-2d4a-4e8b-9c3f-5a1d7e2b8c40"
}
}Returns the generation as it is now. Poll it until status is final.
Poll every 5 seconds until status is succeeded or failed. Polls count toward your rate limit.
curl
curl https://loopling.ai/v1/video/generations/vgen_01J9X6K3M8Q2 \
-H "Authorization: Bearer $LOOPLING_API_KEY"Node
const headers = { Authorization: `Bearer ${process.env.LOOPLING_API_KEY}` }
async function waitForVideo(id) {
for (;;) {
const res = await fetch(`https://loopling.ai/v1/video/generations/${id}`, { headers })
const gen = await res.json()
if (gen.status === 'succeeded') return gen.video // { url, expires_at, duration_seconds, … }
if (gen.status === 'failed') throw new Error(gen.error?.message ?? 'generation failed')
await new Promise((r) => setTimeout(r, 5000))
}
}
const video = await waitForVideo('vgen_01J9X6K3M8Q2')
// video.url is signed and valid for 15 minutes; read the generation again for a fresh one.Python
import os, time, requests
headers = {"Authorization": f"Bearer {os.environ['LOOPLING_API_KEY']}"}
def wait_for_video(generation_id: str) -> dict:
while True:
gen = requests.get(f"https://loopling.ai/v1/video/generations/{generation_id}", headers=headers).json()
if gen["status"] == "succeeded":
return gen["video"] # {"url": …, "expires_at": …, "duration_seconds": …}
if gen["status"] == "failed":
raise RuntimeError(gen.get("error", {}).get("message", "generation failed"))
time.sleep(5)
video = wait_for_video("vgen_01J9X6K3M8Q2")
# video["url"] is signed and valid for 15 minutes; read the generation again for a fresh one.status | Meaning | Look at |
|---|---|---|
queued | Accepted, waiting to start. | ink_reserved |
running | Rendering. | progress, when reported |
succeeded | Done. | video, ink_charged |
failed | Ended without a clip. | error, ink_charged |
A succeeded generation past retention reads result_expired: true and has no video. See Results & retention.
A failed generation names its reason in error.code:
error.code | Meaning |
|---|---|
provider_failed | The provider didn't finish the render. |
timeout | The render ran past its time limit, or contact with it was lost. |
result_persistence_failed | The clip was made but couldn't be stored. |
admission_failed | The generation couldn't be admitted. The submit answered 503 provider_unavailable. |
provider_rejected | The provider refused the task at submit. The submit answered 502 provider_error. |
None of these is charged: ink_charged is 0. Submit again to retry, with a new Idempotency-Key if you send one. See Refunds.
loopling.ai · grows with you, grows itself
hello@loopling.ai · for agents · community · pricing · Enterprise · API · privacy · terms