Luma Ray 2 API parameters: keyframes, loop and callback_url

Luma's video docs list ray-2 and ray-flash-2 with keyframes, loop, concepts and callback_url. Here is each field mapped to the Sume /v1/videos request.

4 min readSume
All posts

Luma's video generation docs, read 2026-10-03, list two models, ray-2 and ray-flash-2, with resolutions from 540p to 4k and request fields for keyframes, loop, concepts and a callback_url. On Sume the same jobs map to POST /v1/videos with frame_images, a callback_url and a catalog model id, and you read the supported ranges from GET /v1/videos/models instead of from a doc page.

One caveat from the research: Luma's docs page lists Ray 2 only and may lag newer Ray releases, so treat the table below as the state of that page on the read date.

What the Luma page says

The facts below are taken from the Luma docs page and nothing else.

Luma video generation docs, ray-2 family (read 2026-10-03)
ItemWhat the page lists
Modelsray-2 and ray-flash-2
Resolutions540p, 720p, 1080, 4k
Request featureskeyframes, loop, concepts, callback_url
ExtendOnly for videos Luma generated
Image inputsMust be CDN URLs

Mapping each field to Sume

Sume follows the OpenRouter video wire on /v1/videos, so a few Luma ideas have a direct counterpart and a few do not.

  • Keyframes: send frame_images with frame_type set to first_frame or last_frame. Each model lists which values it accepts in supported_frame_images.
  • Callback: pass callback_url. It must be HTTPS, and Sume posts its standard job webhook envelope when the job reaches a terminal state.
  • Image inputs: Sume wants public HTTPS URLs, and a URL Sume cannot fetch returns an error such as image_not_fetchable rather than a silent skip.
  • Loop and concepts: the Sume docs list no loop or concepts field on /v1/videos, so describe a seamless loop or a camera move in the prompt instead.
  • Extend: the docs describe no extend endpoint on this route. Chain a new job from a chosen frame if you need a longer shot.

Webhook or polling

Luma exposes a callback_url; Sume does too, and the webhooks guide says to keep polling as a fallback because delivery is an optimization. Sume retries a failed delivery up to 10 times, 30 seconds apart by default, with a 10 second timeout per attempt. Use the job_id as your idempotency key, since a redelivery repeats the same event.

A submit that uses both mechanisms looks like this:

curl -X POST https://api.sume.com/v1/videos \
  -H "Authorization: Bearer $SUME_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Idempotency-Key: ray2-port-001" \
  -d '{
    "model": "sume/auto",
    "prompt": "Slow push-in on a ceramic mug, steam rising, soft window light",
    "duration": 5,
    "resolution": "720p",
    "aspect_ratio": "16:9",
    "callback_url": "https://example.com/hooks/sume"
  }'

Verify the callback

Sume signs the raw body with HMAC SHA 256 over <timestamp>.<raw_body> and sends x-sume-webhook-timestamp and x-sume-webhook-signature: sume-v1=<hex>. This verifier refuses an empty secret and a stale timestamp.

import hashlib, hmac, time

def verify(raw_body: bytes, timestamp: str, header: str, secret: str, tolerance=300) -> bool:
    if not secret:
        raise ValueError("empty webhook secret")
    try:
        ts = int(timestamp)
    except ValueError:
        return False
    if abs(int(time.time()) - ts) > tolerance:
        return False
    signed = f"{ts}.".encode() + raw_body
    digest = hmac.new(secret.encode(), signed, hashlib.sha256).hexdigest()
    expected = "sume-v1=" + digest
    ok = False
    for entry in header.split(","):
        if hmac.compare_digest(entry.strip(), expected):
            ok = True
    return ok

Porting checklist

Work through the list in order before you switch traffic.

  • Replace every CDN image URL with a public HTTPS URL that Sume can fetch without cookies.
  • Move keyframes to frame_images and confirm the model lists them in supported_frame_images.
  • Add an Idempotency-Key to every paid submit so a network retry cannot create a second job.
  • Store the Sume job_id beside your own record, and use it as the idempotency key for webhook handling.
  • Keep a polling fallback running, because a callback can be refused ten times and the job still finishes.
  • Test one failure on purpose, for example an unreachable image URL, and confirm your handler reads the public error.

What to check before porting

Read supported_resolutions, supported_durations and supported_frame_images for the model you pin, because limits are not uniform across the catalog. If you do not want to pin one, model: "sume/auto" lets Sume pick the family, and the job echoes sume/auto. Sume bills workspace USD balance reserved at submit, at provider list times 1.25, and usage.cost on the poll response is the billable amount.

Sources

Related posts

More in Comparisons

All Comparisons posts

Written by Sume