loopling.ai

API reference

Get a video generation

Read a generation’s status, its video link and what it charged.

GET https://loopling.ai/v1/video/generations/{id}

Authorization

Authorization

string · required

Your API key, as Bearer lpl_….

Path parameters

id

string · required

The generation’s id. Another account’s ID answers 404.

Response · 200

id

string

Generation ID, vgen_….

object

enum<string>

Object type.

Available options: video.generation

status

enum<string>

succeeded and failed are final.

Available options: queued, running, succeeded, failed

progress

integer

0–100 while queued or running, when reported.

model

string

The model ID.

created_at

string<date-time>

When it was submitted.

completed_at

string<date-time>

When it reached succeeded or failed.

video

object

The clip. On succeeded, until the result expires.

url

string<uri>

Signed MP4 link. Needs no key; works until expires_at.

expires_at

string<date-time>

When url stops working. Read the generation again for a fresh link.

content_type

string

Always video/mp4.

duration_seconds

number

Seconds billed: the reported length, never more than requested, or the requested length when none is reported.

resolution

string

The requested resolution, or the default.

aspect_ratio

string

The requested aspect ratio, or the default. adaptive comes back as adaptive.

size_bytes

integer

File size in bytes.

result_expired

boolean

true once the clip is past retention. The record stays.

seed

integer

The seed used, when reported.

ink_reserved

integer

Ink held at submit: the most this generation can cost.

usd_payg_reserved

number

ink_reserved in pay-as-you-go USD.

ink_charged

integer

Ink charged, once final. 0 when failed.

usd_payg_charged

number

ink_charged in pay-as-you-go USD.

request

object

The request as accepted: defaults filled in, metadata inside.

error

object

Why it failed. On failed only.

code

string

The reason, such as provider_failed, timeout, result_persistence_failed, admission_failed or provider_rejected.

message

string

A sentence for your logs.

Request

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": …}

Response

200 · running

{
  "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
  }
}

200 · succeeded

{
  "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
  }
}

200 · failed

{
  "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."
  }
}

404

{
  "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.

Polling

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

statusMeaningLook at
queuedAccepted, waiting to start.ink_reserved
runningRendering.progress, when reported
succeededDone.video, ink_charged
failedEnded without a clip.error, ink_charged

A succeeded generation past retention reads result_expired: true and has no video. See Results & retention.

Failed generations

A failed generation names its reason in error.code:

error.codeMeaning
provider_failedThe provider didn't finish the render.
timeoutThe render ran past its time limit, or contact with it was lost.
result_persistence_failedThe clip was made but couldn't be stored.
admission_failedThe generation couldn't be admitted. The submit answered 503 provider_unavailable.
provider_rejectedThe 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.

Explore models

loopling.ai · grows with you, grows itself

hello@loopling.ai · for agents · community · pricing · Enterprise · API · privacy · terms