> ## 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.

# Get Project

> Retrieve detailed information about a specific project including its scenes

Returns comprehensive details about a single video ad project, including all individual scenes, scripts, and generation metadata. Use this endpoint to track project progress or retrieve the final video and scene-level information.

## Authentication

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

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

## Path Parameters

<ParamField path="projectId" type="string" required>
  The unique identifier (UUID) of the project to retrieve. Must be a valid UUID belonging to the authenticated user.
</ParamField>

## Response

<ResponseField name="project" type="object">
  Complete project details including all configuration and output URLs.

  <Expandable title="Project 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 stitched video (MP4) with voiceover, lip sync, and captions. Only available when status is `completed`.
    </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 by ±1 second.
    </ResponseField>

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

    <ResponseField name="quality" type="string | null">
      Video quality setting used for generation. Values: `"standard"`, `"high"`.
    </ResponseField>

    <ResponseField name="tone" type="string | null">
      Ad tone/personality. Examples: `"professional"`, `"conversational"`, `"energetic"`.
    </ResponseField>

    <ResponseField name="energy" type="string | null">
      Ad energy level. Values: `"low"`, `"moderate"`, `"high"`.
    </ResponseField>

    <ResponseField name="pacing" type="string | null">
      Ad pacing style. Values: `"slow"`, `"moderate"`, `"fast"`.
    </ResponseField>

    <ResponseField name="caption_style" type="string | null">
      Caption styling preset applied to the final video.
    </ResponseField>

    <ResponseField name="content_mode" type="string | null">
      Content generation mode used. Values: `"auto"`, `"custom"`.
    </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. Updates frequently during generation.
    </ResponseField>
  </Expandable>
</ResponseField>

<ResponseField name="scenes" type="array">
  Ordered list of individual scenes that make up the final video. Scenes are returned in playback order.

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

    <ResponseField name="scene_order" type="integer">
      Zero-indexed position of this scene in the final video. Scene 0 plays first.
    </ResponseField>

    <ResponseField name="prompt" type="string | null">
      Visual description prompt used to generate this scene's video. May be `null` if generation hasn't started.
    </ResponseField>

    <ResponseField name="script_text" type="string | null">
      Voiceover script spoken during this scene. Used for text-to-speech and caption generation.
    </ResponseField>

    <ResponseField name="output_url" type="string | null">
      HTTPS URL to the individual scene video clip (before final stitching). Only available when scene generation is complete.
    </ResponseField>

    <ResponseField name="status" type="string">
      Scene-level generation status. Common values: `"pending"`, `"generating"`, `"completed"`, `"failed"`.
    </ResponseField>

    <ResponseField name="avatar_id" type="string | null">
      Identifier of the actor/avatar used in this scene. Examples: `"max"`, `"iris"`.
    </ResponseField>

    <ResponseField name="duration_seconds" type="number | null">
      Actual duration of this scene in seconds. May differ slightly from target.
    </ResponseField>

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

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

## Example Requests

<CodeGroup>
  ```bash cURL - Basic Fetch theme={null}
  curl https://app.nouvel.ai/api/v1/projects/550e8400-e29b-41d4-a716-446655440000 \
    -H "Authorization: Bearer nvl_xxxx"
  ```

  ```typescript TypeScript - Basic Fetch theme={null}
  const projectId = '550e8400-e29b-41d4-a716-446655440000';

  const response = await fetch(
    `https://app.nouvel.ai/api/v1/projects/${projectId}`,
    {
      headers: {
        'Authorization': 'Bearer nvl_xxxx'
      }
    }
  );

  const data = await response.json();
  console.log(`Project: ${data.project.title}`);
  console.log(`Status: ${data.project.status}`);
  console.log(`Scenes: ${data.scenes.length}`);
  ```

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

  const data = await response.json();

  // Get full voiceover script in order
  const fullScript = data.scenes
    .sort((a, b) => a.scene_order - b.scene_order)
    .map(scene => scene.script_text)
    .filter(Boolean)
    .join(' ');

  console.log('Full Voiceover Script:', fullScript);
  ```

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

  const data = await response.json();

  if (data.project.status === 'completed' && data.project.final_output_url) {
    // Download the final video
    const videoResponse = await fetch(data.project.final_output_url);
    const videoBlob = await videoResponse.blob();

    // Save to file (Node.js)
    const fs = require('fs');
    const buffer = Buffer.from(await videoBlob.arrayBuffer());
    fs.writeFileSync(`${data.project.title}.mp4`, buffer);
  } else {
    console.log(`Project not ready. Status: ${data.project.status}`);
  }
  ```

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

  project_id = '550e8400-e29b-41d4-a716-446655440000'

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

  data = response.json()
  print(f"Project: {data['project']['title']}")
  print(f"Status: {data['project']['status']}")
  print(f"Scenes: {len(data['scenes'])}")
  ```

  ```python Python - Extract Scene Scripts theme={null}
  import requests

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

  data = response.json()

  # Get full voiceover script in order
  scenes = sorted(data['scenes'], key=lambda s: s['scene_order'])
  full_script = ' '.join(
      scene['script_text']
      for scene in scenes
      if scene['script_text']
  )

  print('Full Voiceover Script:', full_script)
  ```

  ```python Python - Download Final Video theme={null}
  import requests

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

  data = response.json()
  project = data['project']

  if project['status'] == 'completed' and project['final_output_url']:
      # Download the final video
      video_response = requests.get(project['final_output_url'])

      filename = f"{project['title']}.mp4"
      with open(filename, 'wb') as f:
          f.write(video_response.content)

      print(f"Downloaded: {filename}")
  else:
      print(f"Project not ready. Status: {project['status']}")
  ```
</CodeGroup>

## Example Response

```json theme={null}
{
  "project": {
    "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",
    "quality": "high",
    "tone": "professional",
    "energy": "moderate",
    "pacing": "moderate",
    "caption_style": "modern",
    "content_mode": "auto",
    "created_at": "2026-03-15T14:32:10.000Z",
    "updated_at": "2026-03-15T14:48:22.000Z"
  },
  "scenes": [
    {
      "id": "7c9e6679-7425-40de-944b-e07fc1f90ae7",
      "scene_order": 0,
      "prompt": "Professional female spokesperson in modern bright studio, upright posture, direct eye contact with camera, composed confident expression, medium shot showing full shoulders, neutral warm lighting",
      "script_text": "Your skin loses collagen every single day. But what if you could restore it naturally?",
      "output_url": "https://app.nouvel.ai/api/cdn/videos/scene-7c9e6679.mp4",
      "status": "completed",
      "avatar_id": "iris",
      "duration_seconds": 5.2,
      "created_at": "2026-03-15T14:32:11.000Z",
      "updated_at": "2026-03-15T14:38:45.000Z"
    },
    {
      "id": "8d1f7789-8536-51ef-a55c-f18gd2g01bf8",
      "scene_order": 1,
      "prompt": "Close-up of hands pouring marine collagen powder into clear glass of water on modern kitchen counter, natural morning light, product packaging visible in background",
      "script_text": "Our marine collagen is clinically proven to boost skin elasticity by up to 40% in just 8 weeks.",
      "output_url": "https://app.nouvel.ai/api/cdn/videos/scene-8d1f7789.mp4",
      "status": "completed",
      "avatar_id": null,
      "duration_seconds": 4.8,
      "created_at": "2026-03-15T14:32:11.000Z",
      "updated_at": "2026-03-15T14:39:12.000Z"
    },
    {
      "id": "9e2g8899-9647-62fg-b66d-g29he3h12cg9",
      "scene_order": 2,
      "prompt": "Professional female spokesperson in modern bright studio, upright posture, direct eye contact with camera, warm engaged expression, medium shot showing full shoulders",
      "script_text": "Join thousands of women who've transformed their skin. Try it risk-free today.",
      "output_url": "https://app.nouvel.ai/api/cdn/videos/scene-9e2g8899.mp4",
      "status": "completed",
      "avatar_id": "iris",
      "duration_seconds": 5.0,
      "created_at": "2026-03-15T14:32:11.000Z",
      "updated_at": "2026-03-15T14:40:03.000Z"
    }
  ]
}
```

## Error Responses

<ResponseField name="404 Not Found" type="object">
  Returned when the project doesn't exist or doesn't belong to the authenticated user.

  ```json theme={null}
  {
    "error": "Project not found"
  }
  ```
</ResponseField>

<ResponseField name="401 Unauthorized" type="object">
  Returned when the API key is missing, invalid, or lacks the required permissions.

  ```json theme={null}
  {
    "error": "Unauthorized"
  }
  ```
</ResponseField>

## Notes

<Note>
  **Security:** Projects can only be accessed by their owner. API keys are scoped to individual user accounts, and attempting to access another user's project will return a 404 error.
</Note>

<Info>
  **Scene URLs vs Final URL:** The individual scene `output_url` values point to raw scene clips before final processing. The project-level `final_output_url` is the fully processed video with continuous voiceover, lip sync, and captions applied. Always use `final_output_url` for production purposes.
</Info>

<Note>
  **Polling for Completion:** When monitoring project progress, poll this endpoint every 10 seconds until the `status` field becomes `completed` or `failed`. The `updated_at` timestamp changes whenever generation progresses.
</Note>

<Info>
  **Scene Order:** Scenes are always returned in playback order sorted by `scene_order`. The final video plays scene 0 first, then scene 1, etc.
</Info>

<Note>
  **Avatar Scenes vs Product Scenes:** Scenes with an `avatar_id` feature a human spokesperson. Scenes without an `avatar_id` (null) are typically product demonstration shots or B-roll footage.
</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>
