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

# Output

> Access project timeline, assets, variations, memory, and render or share the final result.

## Get timeline

<br />

```
GET /projects/:id/timeline
```

Returns the full timeline structure: scenes, audio tracks, overlays, and captions.

| Parameter      | Type   | Description                                                      |
| -------------- | ------ | ---------------------------------------------------------------- |
| `variation_id` | string | Fetch a specific variation's timeline instead of the active one. |

### Response `200`

```json theme={"dark"}
{
  "timeline": {
    "duration_seconds": 15.2,
    "aspect_ratio": "16:9",
    "skills": [],
    "scenes": [
      {
        "id": "scene_001",
        "ref": "a1b2c3d4",
        "type": "video",
        "position": 0,
        "duration": 4.0,
        "description": "Opening shot of the product",
        "image_url": "https://...",
        "video_url": "https://...",
        "video_model": "seedance-2.0",
        "image_model": "nano-banana-pro",
        "prompt": "Opening shot of the product on a clean background...",
        "volume": 1,
        "fade_in": 0.5,
        "fade_out": null
      }
    ],
    "audio": {
      "voiceover": {
        "url": "https://...",
        "duration": 12.5,
        "voice": "Isabella",
        "voice_id": "voice_001",
        "language": "en",
        "script": "Your voiceover script here..."
      },
      "music": {
        "url": "https://...",
        "duration": 15.2,
        "genre": "ambient",
        "mood": "warm",
        "bpm": 72,
        "role": "background",
        "instrumental": true
      },
      "tracks": [
        {
          "id": "track_001",
          "type": "voiceover",
          "url": "https://...",
          "duration": 12.5,
          "volume": 100,
          "start_time": 0.5,
          "name": "Main narration",
          "voice": "Isabella",
          "voice_id": "voice_001",
          "language": "en",
          "script": "Your voiceover script here..."
        }
      ]
    },
    "overlays": [
      {
        "id": "text-0",
        "type": "text",
        "content": "Your Brand",
        "start_time": 12.0,
        "duration": 3.0,
        "position": "bottom-center",
        "font_size": 48,
        "color": "#FFFFFF",
        "background_color": "rgba(0,0,0,0.5)"
      }
    ],
    "captions": {
      "enabled": true,
      "preset": "clean"
    }
  }
}
```

## Get assets

<br />

```
GET /projects/:id/assets
```

Returns all generated assets (images, videos, audio) for the project. Each asset has a `ref`, an 8-character short identifier that links assets to scenes on the timeline.

| Parameter | Type    | Default | Description              |
| --------- | ------- | ------- | ------------------------ |
| `limit`   | integer | 20      | Results per page. 1–200. |
| `offset`  | integer | 0       | Pagination offset.       |

### Response `200`

```json theme={"dark"}
{
  "assets": [
    {
      "ref": "x7y8z9a0",
      "type": "video",
      "url": "https://...",
      "model": "seedance-2.0",
      "prompt": "Opening shot of the product on a clean background...",
      "duration": 5.0,
      "aspect_ratio": "16:9",
      "source_image_url": "https://...",
      "source_video_url": null,
      "reference_image_url": null,
      "created_at": "2025-03-15T10:32:00Z"
    }
  ],
  "total": 24,
  "limit": 20,
  "offset": 0
}
```

## List variations

<br />

```
GET /projects/:id/variations
```

Returns all variations for a project. Variations are read-only via the API. Create, switch, and delete them by sending messages to the agent.

### Response `200`

```json theme={"dark"}
{
  "variations": [
    {
      "id": "var_001",
      "title": "Original",
      "description": null,
      "aspect_ratio": "16:9",
      "language": "en",
      "scene_count": 4,
      "is_active": true,
      "created_at": "2025-03-15T10:30:00Z"
    },
    {
      "id": "var_002",
      "title": "TikTok Version",
      "description": "Portrait format for social",
      "aspect_ratio": "9:16",
      "language": "en",
      "scene_count": 4,
      "is_active": false,
      "created_at": "2025-03-15T10:40:00Z"
    }
  ]
}
```

To create or switch variations, send a message to the agent:

```json theme={"dark"}
{ "message": "Create a 9:16 version for TikTok" }
{ "message": "Switch to variation var_002" }
{ "message": "Duplicate the current variation" }
```

Use `GET /projects/:id/timeline?variation_id=var_002` to inspect a non-active variation's timeline without switching.

## Get agent memory

<br />

```
GET /projects/:id/memory
```

Read the agent's working memory for this project.

### Response `200`

```json theme={"dark"}
{
  "sections": {
    "creative": {
      "content": "Markdown summary of the locked creative direction and production settings...",
      "tokens": 142
    },
    "todos": {
      "content": "Checklist tracking what's done and what's next...",
      "tokens": 98
    },
    "assets": {
      "content": "Structured ledger of characters, products, environments, and references...",
      "tokens": 67
    }
  },
  "total_tokens": 307
}
```

The agent maintains three memory sections per project:

* **Creative** — Markdown of the locked creative direction and chosen production settings
* **Todos** — Checklist of what's done and what's next
* **Assets** — Structured ledger of characters, products, environments, and references the agent is using

Memory is per-project (shared across all variations). The agent condenses automatically as sections grow.

Separately, **learned preferences** persist across all projects. These are patterns the agent picks up from your feedback about style and production choices. Manage these via the [account endpoints](/api/account#learned-preferences).

## Render video

<br />

```
POST /projects/:id/render
```

Trigger a final video render. Composites all timeline content (scenes, audio, overlays, captions) into a single video file. Only valid when status is `idle`.

### Request body

| Parameter | Type   | Default | Description                                                                |
| --------- | ------ | ------- | -------------------------------------------------------------------------- |
| `quality` | string | `1080p` | `1080p` or `4k`. 1080p is free (rate-limited per day). 4K charges credits. |

### Response `202`

```json theme={"dark"}
{
  "id": "proj_abc123",
  "status": "rendering",
  "quality": "1080p"
}
```

Poll the project status. When rendering completes, the status returns to `idle` and `assembled_url` contains the video URL.

<Note>
  Rendered video URLs expire after 24 hours. Create a share link for a permanent URL, or render again.
</Note>

## Create share link

<br />

```
POST /projects/:id/share
```

Create a permanent, public URL for a rendered video. Requires a completed render.

### Request body

| Parameter     | Type   | Description                         |
| ------------- | ------ | ----------------------------------- |
| `title`       | string | Optional title for the shared page. |
| `description` | string | Optional description.               |

### Response `201`

```json theme={"dark"}
{
  "share_url": "https://eversince.ai/share/abc123",
  "video_url": "https://..."
}
```

The `video_url` from a share link does not expire.

## Upload files

Upload reference media (images, videos, audio) for use in project creation or messages.

### Step 1: Get a presigned upload URL

```
POST /uploads
```

| Parameter      | Type    | Required | Description                                  |
| -------------- | ------- | -------- | -------------------------------------------- |
| `file_name`    | string  | Yes      | Original file name.                          |
| `content_type` | string  | Yes      | MIME type (e.g., `image/jpeg`, `video/mp4`). |
| `file_size`    | integer | Yes      | File size in bytes.                          |

**Size limits:** Images 10 MB, Videos 500 MB, Audio 50 MB.

**Accepted types:** `image/jpeg`, `image/jpg`, `image/png`, `image/webp`, `video/mp4`, `video/webm`, `video/quicktime`, `video/x-msvideo`, `audio/mpeg`, `audio/mp3`, `audio/wav`, `audio/mp4`, `audio/m4a`.

#### Response `200`

```json theme={"dark"}
{
  "upload_url": "https://...",
  "r2_key": "uploads/abc123/image.jpg",
  "expires_in": 3600
}
```

### Step 2: Upload the file

```
PUT {upload_url}
```

Upload the file directly to the presigned URL with the matching `Content-Type` header.

### Step 3: Confirm the upload

```
POST /uploads/confirm
```

| Parameter      | Type    | Required | Description               |
| -------------- | ------- | -------- | ------------------------- |
| `r2_key`       | string  | Yes      | The `r2_key` from step 1. |
| `file_name`    | string  | Yes      | Original file name.       |
| `file_size`    | integer | Yes      | File size in bytes.       |
| `content_type` | string  | Yes      | MIME type.                |

#### Response `201`

```json theme={"dark"}
{
  "upload_id": "upl_abc123",
  "type": "image"
}
```

Use the `upload_id` as a reference when creating projects or sending messages:

```json theme={"dark"}
{
  "brief": "Create an ad featuring this product",
  "references": [{ "upload_id": "upl_abc123" }]
}
```

### Full upload example

<CodeGroup>
  ```bash curl theme={"dark"}
  # 1. Get presigned URL
  PRESIGN=$(curl -s -X POST https://eversince.ai/api/v1/uploads \
    -H "Authorization: Bearer $EVERSINCE_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "file_name": "product.jpg",
      "content_type": "image/jpeg",
      "file_size": 245000
    }')

  UPLOAD_URL=$(echo $PRESIGN | jq -r '.upload_url')
  R2_KEY=$(echo $PRESIGN | jq -r '.r2_key')

  # 2. Upload the file
  curl -X PUT "$UPLOAD_URL" \
    -H "Content-Type: image/jpeg" \
    --data-binary @product.jpg

  # 3. Confirm
  curl -X POST https://eversince.ai/api/v1/uploads/confirm \
    -H "Authorization: Bearer $EVERSINCE_API_KEY" \
    -H "Content-Type: application/json" \
    -d "{
      \"r2_key\": \"$R2_KEY\",
      \"file_name\": \"product.jpg\",
      \"file_size\": 245000,
      \"content_type\": \"image/jpeg\"
    }"

  # Response: { "upload_id": "upl_abc123", "type": "image" }
  ```

  ```python Python theme={"dark"}
  import os

  file_path = "product.jpg"
  file_size = os.path.getsize(file_path)

  # 1. Get presigned URL
  presign = requests.post(f"{BASE}/uploads", headers=headers, json={
      "file_name": "product.jpg",
      "content_type": "image/jpeg",
      "file_size": file_size
  }).json()

  # 2. Upload the file
  with open(file_path, "rb") as f:
      requests.put(presign["upload_url"],
                   data=f,
                   headers={"Content-Type": "image/jpeg"})

  # 3. Confirm
  upload = requests.post(f"{BASE}/uploads/confirm", headers=headers, json={
      "r2_key": presign["r2_key"],
      "file_name": "product.jpg",
      "file_size": file_size,
      "content_type": "image/jpeg"
  }).json()

  # Use in project creation
  requests.post(f"{BASE}/projects", headers=headers, json={
      "brief": "Create an ad featuring this product",
      "references": [{"upload_id": upload["upload_id"]}]
  })
  ```

  ```javascript JavaScript theme={"dark"}
  const fs = require("fs");

  const filePath = "product.jpg";
  const fileSize = fs.statSync(filePath).size;

  // 1. Get presigned URL
  const presign = await fetch(`${BASE}/uploads`, {
    method: "POST",
    headers,
    body: JSON.stringify({
      file_name: "product.jpg",
      content_type: "image/jpeg",
      file_size: fileSize,
    }),
  }).then((r) => r.json());

  // 2. Upload the file
  await fetch(presign.upload_url, {
    method: "PUT",
    headers: { "Content-Type": "image/jpeg" },
    body: fs.readFileSync(filePath),
  });

  // 3. Confirm
  const upload = await fetch(`${BASE}/uploads/confirm`, {
    method: "POST",
    headers,
    body: JSON.stringify({
      r2_key: presign.r2_key,
      file_name: "product.jpg",
      file_size: fileSize,
      content_type: "image/jpeg",
    }),
  }).then((r) => r.json());

  // Use in project creation
  await fetch(`${BASE}/projects`, {
    method: "POST",
    headers,
    body: JSON.stringify({
      brief: "Create an ad featuring this product",
      references: [{ upload_id: upload.upload_id }],
    }),
  });
  ```
</CodeGroup>
