> ## Documentation Index
> Fetch the complete documentation index at: https://docs.motioness.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Your first asset

End-to-end walkthrough — set up a project, hit the proxy, see the mp4 in your page.

# Your first asset

This guide ships an animated mp4 to a real page. We'll do it three different ways — pick whichever fits your stack.

**Sign up + grab your project key**

[Create an account](https://motioness.com/sign-up). Dashboard creates a default project for you. Open Project → Settings → Proxy and copy the **Project key** (`pk_…`).

  **Set allowed origins**

Add the origin where you'll embed the proxy URL (e.g. `https://localhost:3000` for dev, `https://acme.com` for prod). Without this, every request returns 403.

    For server-rendered URLs across origins, switch to [signed mode](/concepts/allowlist-vs-signed) instead.

  **Pick a source image**

Any public URL works. For this walkthrough, we'll use `https://cdn.acme.com/hero.png`. Replace it with one of yours.

    The image must be publicly fetchable from Cloudflare — no auth headers, no IP allowlists. Sources behind auth need to be uploaded via [`POST /api/v1/upload`](/api/upload/upload) first.

  **Construct the proxy URL**

```text
    https://motioness.com/v1/pk_YOUR_KEY/cdn.acme.com/hero.png.mp4
    ```

    Strip the `https://` from the source URL. Keep the rest as-is. End with `.mp4` for video, `.jpg` for poster.

  **Embed it**

The React component is the most polished surface — it ships with hover effects, lazy loading, callbacks, and SSR-safe progressive enhancement. Use plain HTML only when you can't run JS.

    **React (recommended)**

```bash
        npm install @motioness/proxy-client
        ```

        ```tsx
        import { MotionessImg } from '@motioness/proxy-client/react';

        export function Hero() {
          return (
            <MotionessImg
              projectKey="pk_YOUR_KEY"
              src="https://cdn.acme.com/hero.png"
              motion="medium"
              durSeconds={4}
              style={{ width: '100%' }}
            />
          );
        }
        ```

      **Web Component**

```html
        <script type="module" src="https://motioness.com/proxy-client/element.js"></script>

        <motioness-img
          project-key="pk_YOUR_KEY"
          src="https://cdn.acme.com/hero.png"
          motion="medium"
          dur-seconds="4"
          style="width: 100%;"
        />
        ```

        Same effects as the React binding without React.

      **Plain HTML**

```html
        <video
          src="https://motioness.com/v1/pk_YOUR_KEY/cdn.acme.com/hero.png.mp4"
          poster="https://motioness.com/v1/pk_YOUR_KEY/cdn.acme.com/hero.png.jpg"
          autoplay muted loop playsinline
          style="width: 100%; height: auto;"
        />
        ```

        No hover effects, no lazy load. For OG cards, RSS, MDX.

  **Watch the first request**

The `<video>` element will:

    1. Show the poster jpg immediately (the source image).
    2. Hit the mp4 URL — first time, server returns `202 Accepted` and `Retry-After: 30`.
    3. After ~20-60 seconds, the mp4 finalizes; the next request streams it.

    For faster feedback during development, append `?wait_ms=8000`:

    ```text
    …/hero.png.mp4?wait_ms=8000
    ```

    Server long-polls up to 8 seconds before returning 202.

  **Inspect the lifecycle (optional)**

Open browser devtools → Network → click the mp4 row. Look at response headers:

    ```text
    X-Motioness-Asset-Id: a25b330a71e2bc6b
    X-Motioness-Stage: queued | stage1 | stage2 | merge | ready
    X-Motioness-Eta-Ms: 28000
    X-Request-Id: req_a1b2c3d4
    Retry-After: 30
    ```

    To watch the asset finalize live:

    ```bash
    curl -N "https://motioness.com/v1/pk_YOUR_KEY/events/a25b330a71e2bc6b"
    ```

    Each event arrives as `id: <ms> / event: <type> / data: <json>`. See [SSE streaming](/guides/sse-streaming).

  **Refresh**

Reload the page. The mp4 streams from the edge cache in ~5ms. The asset is permanent — same URL, same bytes, forever.

## What went wrong?

| Symptom | Likely cause | Fix |
|---|---|---|
| 403 on every request | Origin not in allowlist | Add your origin in Project → Settings, or use signed mode |
| 403 with "unknown project key" | Wrong `pk_…` value | Double-check the dashboard |
| 415 unsupported type | Source isn't png/jpg/webp | Re-encode or upload via `/api/v1/upload` |
| 413 file too large | Source > 10 MB | Resize before fetching |
| 429 monthly limit reached | Free tier exhausted | Upgrade or wait until reset |
| 502 last generation failed | Vision/i2v failed permanently | Check `error_code` in `asset.failed` event; try regenerate with `?prompt=…` |

## Next

**[Webhooks](/guides/webhooks)**

Get notified when assets finalize.
  **[Signed URLs](/guides/signed-urls)**

Generate short-lived URLs server-side.
  **[Regenerate](/guides/regenerate)**

Iterate without changing the URL.
  **[Errors + retries](/guides/errors-and-retries)**

Understand the failure surface.