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

# List Projects

> Retrieve a paginated list of your video ad projects

Returns a paginated list of all video ad projects created by the authenticated user. Results are sorted by creation date (newest first) and can be filtered by project status.

## Authentication

This endpoint requires a valid API key with the `projects:read` permission.

```bash theme={null}
Authorization: Bearer nvl_xxxx
```

## Query Parameters

<ParamField query="page" type="integer" default={1}>
  Page number for pagination (1-indexed). Must be a positive integer.
</ParamField>

<ParamField query="limit" type="integer" default={20}>
  Number of results to return per page. Must be between 1 and 100.
</ParamField>

<ParamField query="status" type="string">
  Filter projects by their current status. Omit to return all projects.

  **Allowed values:**

  * `generating` - Video scenes are being generated
  * `post_processing` - Generating voiceover and lip sync
  * `stitching` - Combining scenes with audio and captions
  * `completed` - Project is ready with final video
  * `failed` - Generation encountered an unrecoverable error
  * `partial` - Some scenes completed but project failed overall
</ParamField>

## Response

<ResponseField name="projects" type="array">
  List of project objects matching the query criteria.

  <Expandable title="Project object properties">
    <ResponseField name="id" type="string">
      Unique project identifier (UUID format).
    </ResponseField>

    <ResponseField name="title" type="string">
      Human-readable project title.
    </ResponseField>

    <ResponseField name="description" type="string | null">
      AI-generated description of the video ad concept. May be `null` for projects still in generation.
    </ResponseField>

    <ResponseField name="status" type="string">
      Current project status. One of: `generating`, `post_processing`, `stitching`, `completed`, `failed`, `partial`.
    </ResponseField>

    <ResponseField name="final_output_url" type="string | null">
      HTTPS URL to the final MP4 video file. Only available when `status` is `completed`. URL is publicly accessible but unguessable.
    </ResponseField>

    <ResponseField name="aspect_ratio" type="string | null">
      Video aspect ratio. Common values: `"9:16"` (vertical/mobile), `"1:1"` (square), `"16:9"` (horizontal/desktop).
    </ResponseField>

    <ResponseField name="target_duration_seconds" type="integer | null">
      Target video duration in seconds. Actual duration may vary slightly.
    </ResponseField>

    <ResponseField name="product_url" type="string | null">
      Original product URL provided when creating the project.
    </ResponseField>

    <ResponseField name="created_at" type="string">
      ISO 8601 timestamp when the project was created.
    </ResponseField>

    <ResponseField name="updated_at" type="string">
      ISO 8601 timestamp when the project was last modified.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="pagination" type="object">
  Pagination metadata for navigating through results.

  <Expandable title="Pagination properties">
    <ResponseField name="page" type="integer">
      Current page number (1-indexed).
    </ResponseField>

    <ResponseField name="limit" type="integer">
      Number of results returned per page.
    </ResponseField>

    <ResponseField name="total" type="integer">
      Total number of projects matching the query.
    </ResponseField>

    <ResponseField name="totalPages" type="integer">
      Total number of pages available.
    </ResponseField>

    <ResponseField name="hasMore" type="boolean">
      Whether additional pages exist beyond the current page.
    </ResponseField>
  </Expandable>
</ResponseField>

## Example Requests

<CodeGroup>
  ```bash cURL - Basic Listing theme={null}
  curl https://app.nouvel.ai/api/v1/projects \
    -H "Authorization: Bearer nvl_xxxx"
  ```

  ```bash cURL - Filter by Status theme={null}
  curl "https://app.nouvel.ai/api/v1/projects?status=completed&limit=10" \
    -H "Authorization: Bearer nvl_xxxx"
  ```

  ```bash cURL - Pagination theme={null}
  curl "https://app.nouvel.ai/api/v1/projects?page=2&limit=50" \
    -H "Authorization: Bearer nvl_xxxx"
  ```

  ```typescript TypeScript - Basic Listing theme={null}
  const response = await fetch('https://app.nouvel.ai/api/v1/projects', {
    headers: {
      'Authorization': 'Bearer nvl_xxxx'
    }
  });

  const data = await response.json();
  console.log(`Found ${data.pagination.total} projects`);
  ```

  ```typescript TypeScript - Filter Completed Projects theme={null}
  const response = await fetch(
    'https://app.nouvel.ai/api/v1/projects?status=completed',
    {
      headers: {
        'Authorization': 'Bearer nvl_xxxx'
      }
    }
  );

  const data = await response.json();
  const completedVideos = data.projects.map(p => ({
    id: p.id,
    title: p.title,
    videoUrl: p.final_output_url
  }));
  ```

  ```typescript TypeScript - Pagination Loop theme={null}
  async function getAllProjects() {
    const allProjects = [];
    let page = 1;
    let hasMore = true;

    while (hasMore) {
      const response = await fetch(
        `https://app.nouvel.ai/api/v1/projects?page=${page}&limit=100`,
        {
          headers: {
            'Authorization': 'Bearer nvl_xxxx'
          }
        }
      );

      const data = await response.json();
      allProjects.push(...data.projects);
      hasMore = data.pagination.hasMore;
      page++;
    }

    return allProjects;
  }
  ```

  ```python Python - Basic Listing theme={null}
  import requests

  response = requests.get(
      'https://app.nouvel.ai/api/v1/projects',
      headers={'Authorization': 'Bearer nvl_xxxx'}
  )

  data = response.json()
  print(f"Found {data['pagination']['total']} projects")
  ```

  ```python Python - Filter by Status theme={null}
  import requests

  response = requests.get(
      'https://app.nouvel.ai/api/v1/projects',
      params={'status': 'completed', 'limit': 10},
      headers={'Authorization': 'Bearer nvl_xxxx'}
  )

  data = response.json()
  for project in data['projects']:
      print(f"{project['title']}: {project['final_output_url']}")
  ```

  ```python Python - Pagination Loop theme={null}
  import requests

  def get_all_projects():
      all_projects = []
      page = 1
      has_more = True

      while has_more:
          response = requests.get(
              'https://app.nouvel.ai/api/v1/projects',
              params={'page': page, 'limit': 100},
              headers={'Authorization': 'Bearer nvl_xxxx'}
          )

          data = response.json()
          all_projects.extend(data['projects'])
          has_more = data['pagination']['hasMore']
          page += 1

      return all_projects
  ```
</CodeGroup>

## Example Response

```json theme={null}
{
  "projects": [
    {
      "id": "550e8400-e29b-41d4-a716-446655440000",
      "title": "Premium Collagen Ad - Vertical",
      "description": "A compelling 15-second ad showcasing the benefits of marine collagen supplement with professional spokesperson and product demo.",
      "status": "completed",
      "final_output_url": "https://app.nouvel.ai/api/cdn/videos/final-550e8400.mp4",
      "aspect_ratio": "9:16",
      "target_duration_seconds": 15,
      "product_url": "https://example.com/products/collagen",
      "created_at": "2026-03-15T14:32:10.000Z",
      "updated_at": "2026-03-15T14:48:22.000Z"
    },
    {
      "id": "6ba7b810-9dad-11d1-80b4-00c04fd430c8",
      "title": "Skincare Serum - Instagram",
      "description": null,
      "status": "generating",
      "final_output_url": null,
      "aspect_ratio": "9:16",
      "target_duration_seconds": 15,
      "product_url": "https://example.com/products/serum",
      "created_at": "2026-03-15T14:20:05.000Z",
      "updated_at": "2026-03-15T14:25:18.000Z"
    }
  ],
  "pagination": {
    "page": 1,
    "limit": 20,
    "total": 42,
    "totalPages": 3,
    "hasMore": true
  }
}
```

## Notes

<Note>
  **Security:** Only projects belonging to the authenticated user are returned. API keys are scoped to individual user accounts.
</Note>

<Info>
  **Video Availability:** The `final_output_url` is only populated when the project status is `completed`. For projects still in progress, this field will be `null`.
</Info>

<Note>
  **Sorting:** Results are always sorted by `created_at` in descending order (newest projects first). Custom sorting is not currently supported.
</Note>

<Info>
  **Rate Limiting:** This endpoint is rate-limited to 60 requests per minute per API key. See [Rate Limits](/api-reference/rate-limits) for details.
</Info>
