Public proxy URL

This isn't a typical REST endpoint — it's a URL pattern. Every Motioness embed (<img>, <video>, OG tags, RSS, MDX) is just a hand-crafted URL on motioness.com.

text
GET https://motioness.com/v1/{projectKey}/{srcWithoutScheme}.{format}[?params]

Auth

Two modes per project. Pick one:

  • Allowlist — source URL plain text, origin must match allowed_origins.
  • Signed — source URL base64url-encoded, request signed with HMAC-SHA256.

See allowlist vs signed.

Path

SegmentDescription
projectKeyPublic project key (pk_…)
srcWithoutSchemeSource URL with https:// stripped (allowlist) or base64url-encoded (signed)
format.mp4 for video, .jpg for poster

Query parameters

ParamTypeDefaultEffect
motionsubtle / medium / kineticproject defaultMotion intensity
modeloop / animate-in / animate-on-hoverproject defaultPlayback shape
durint 2..8project defaultOutput length (seconds)
promptstring ≤500Override brand-aware prompt
seedintDeterministic seed
aspect1:1 / 16:9 / 9:16 / preservepreserveOutput aspect (seedance only)
idemstringForce distinct asset from same source
wait_msint 0..100000Long-poll deadline
sighexHMAC signature (signed mode only)
expunix secondsSignature expiry (signed mode only)

Responses

200 (mp4 ready, served from R2 / edge cache)

text
HTTP/1.1 200 OKContent-Type: video/mp4X-Motioness-Asset-Id: a25b330a71e2bc6bX-Motioness-Stage: readyX-Motioness-Loop: nativeX-Request-Id: req_abc12345Cache-Control: public, max-age=31536000, immutablecf-cache-status: HIT

200 (jpg poster)

text
HTTP/1.1 200 OKContent-Type: image/jpegCache-Control: public, max-age=31536000, immutable

202 (mp4 generating)

http
HTTP/1.1 202 AcceptedRetry-After: 30X-Motioness-Asset-Id: a25b…X-Motioness-Stage: queuedX-Motioness-Eta-Ms: 28000Content-Type: application/json{ "status": "pending", "asset_id": "a25b330a71e2bc6b", "eta_seconds": 28}

403 (forbidden)

json
{ "error": "origin not in allowlist" }{ "error": "unknown project key" }{ "error": "invalid signature" }{ "error": "signing not configured or signature missing" }

415 / 413 (source rejected)

json
{ "error": "unsupported type: image/svg+xml — png/jpeg/webp only" }{ "error": "file exceeds 10 MB limit" }

429 (quota)

json
{ "error": "monthly limit reached", "upgrade_url": "https://motioness.com/pricing" }

502 (terminal failure)

json
{ "error": "last generation failed", "asset_id": "a25b…", "hint": "POST /api/v1/regenerate/{asset_id}"}

SSE companion

For live status, the public proxy also exposes:

text
GET /v1/{projectKey}/events/{assetId}

See SSE streaming.

Why this isn't in the OpenAPI spec

The proxy URL has variable path segments (the source URL itself is part of the path) and a polymorphic response (mp4 bytes vs JSON). OpenAPI's paths model doesn't express that cleanly. We document it manually here and keep the structured REST API in the auto-generated reference.

Ask a question... ⌘I