---
title: "Copilot API"
description: "Reference for the Imagen Copilot API: apply prompt-based AI enhancements to individual photos after editing, chain versions, reset, and finalize for download."
canonical: https://api-docs.imagen-ai.com/docs/reference/copilot/
last-updated: 2026-08-27
---

# Copilot API

The Copilot API lets you apply prompt-based AI enhancements to individual photos
after the initial edit completes. This is the same capability as the AI Assistant
in the real estate web app. You send a natural-language instruction, and Imagen
returns an enhanced version of the image. Edits chain, so you can build on
previous results or reset to an earlier state.

Copilot is a general post-edit capability. Its endpoints sit on `/v1/projects/`
(no `i2i` prefix), so it works on top of any completed project regardless of how
it was edited.

> **Export the project first** The project must have reached `Completed` status, and you must call `export_project` (Python) / `exportProject` (Node) on it before any Copilot call - including `apply_copilot` and `get_ai_tools`. Export prepares the edited versions Copilot builds on; without it these calls fail. You only need to export once per project.

## Endpoints

| Method | Endpoint | Purpose |
| --- | --- | --- |
| POST | `/v1/projects/{uuid}/images/{filename}/copilot` | Apply a prompt-based enhancement to one image |
| POST | `/v1/projects/{uuid}/images/{filename}/enhance` | Apply a preset enhancement to one image |
| GET | `/v1/projects/{uuid}/ai-tools` | List the AI enhancement (preset) tools available for the project |
| DELETE | `/v1/projects/{uuid}/images/{filename}/copilot` | Reset all Copilot edits on one image |
| POST | `/v1/projects/{uuid}/finalize` | Lock in Copilot edits and prepare the project for download |

## 1. Send a prompt

`POST /v1/projects/PROJECT_UUID/images/FILENAME/copilot`

For the first call, set `parent_version_id` to `null`.

> **Copilot calls are synchronous** The endpoint waits for the enhancement to complete and returns the result directly. No polling required.

```curl
curl -X POST 'https://api.imagen-ai.com/v1/projects/$PROJECT_UUID/images/DSC_0001.JPEG/copilot' \
  --header 'x-api-key: $IMAGEN_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "instruction": "make the sky more blue",
    "parent_version_id": null,
    "project_source": "REGULAR"
  }'
```

```python
# Export once before any Copilot call - required.
await client.export_project(project_uuid)

result = await client.apply_copilot(
    project_uuid,
    "DSC_0001.JPEG",
    "make the sky more blue",
)
version_id = result.version_id
```

```typescript
// Export once before any Copilot call - required.
await client.exportProject(projectUuid);

const result = await client.applyCopilot(
  projectUuid,
  'DSC_0001.JPEG',
  'make the sky more blue'
);
const { versionId, enhancedImageUrl } = result;
```

```go
import imagen "github.com/imagenai/imagen-ai-sdk/sdks/go"

// Export once before any Copilot call - required.
if err := client.ExportAndWait(ctx, projectUUID, nil); err != nil {
    log.Fatal(err)
}

result, _ := client.Copilot(ctx, projectUUID, "DSC_0001.JPEG", imagen.CopilotRequest{
    Instruction:   "make the sky more blue",
    ProjectSource: imagen.ProjectSourceRegular,
})
fmt.Println("version:", result.VersionID)
```

```java
import java.net.URI;

var body = """
    {
        "instruction": "make the sky more blue",
        "parent_version_id": null,
        "project_source": "REGULAR"
    }
    """;
var request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.imagen-ai.com/v1/projects/" + projectUuid + "/images/DSC_0001.JPEG/copilot"))
    .header("x-api-key", System.getenv("IMAGEN_API_KEY"))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(body))
    .build();
var response = HttpClient.newHttpClient()
    .send(request, HttpResponse.BodyHandlers.ofString());
```

```ruby
require 'net/http'
require 'json'
require 'uri'

uri = URI("https://api.imagen-ai.com/v1/projects/#{project_uuid}/images/DSC_0001.JPEG/copilot")
req = Net::HTTP::Post.new(uri)
req['x-api-key'] = ENV['IMAGEN_API_KEY']
req['Content-Type'] = 'application/json'
req.body = {
  instruction: 'make the sky more blue',
  parent_version_id: nil,
  project_source: 'REGULAR',
}.to_json

res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
version_id = JSON.parse(res.body)['version_id']
```

```php
<?php
$url = 'https://api.imagen-ai.com/v1/projects/' . $projectUuid . '/images/DSC_0001.JPEG/copilot';
$ch = curl_init($url);
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_POST => true,
  CURLOPT_HTTPHEADER => [
    'x-api-key: ' . getenv('IMAGEN_API_KEY'),
    'Content-Type: application/json',
  ],
  CURLOPT_POSTFIELDS => json_encode([
    'instruction' => 'make the sky more blue',
    'parent_version_id' => null,
    'project_source' => 'REGULAR',
  ]),
]);
$response = curl_exec($ch);
curl_close($ch);
$version_id = json_decode($response, true)['version_id'];
```

```csharp
using System.Net.Http;
using System.Text;
using System.Text.Json;

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key",
    Environment.GetEnvironmentVariable("IMAGEN_API_KEY"));

var payload = JsonSerializer.Serialize(new {
    instruction = "make the sky more blue",
    parent_version_id = (int?)null,
    project_source = "REGULAR",
});
var content = new StringContent(payload, Encoding.UTF8, "application/json");
var response = await client.PostAsync(
    $"https://api.imagen-ai.com/v1/projects/{projectUuid}/images/DSC_0001.JPEG/copilot", content);
```
```json
{
  "status": "SUCCESS",
  "version_id": 123,
  "enhanced_image_url": "https://<s3-presigned>"
}
```

Save the `version_id`. Pass it as `parent_version_id` on the next call to build on
this result.

## 2. Chain edits

Each prompt creates a new version that builds on the previous one. Pass the prior
`version_id` as `parent_version_id`. The response returns a new `version_id` such as `124`. To branch from an earlier point, pass that earlier `version_id`
instead. Subsequent edits will overwrite the branch you didn't keep.

```curl
curl -X POST 'https://api.imagen-ai.com/v1/projects/$PROJECT_UUID/images/DSC_0001.JPEG/copilot' \
  --header 'x-api-key: $IMAGEN_API_KEY' \
  --header 'Content-Type: application/json' \
  --data '{
    "instruction": "brighten the interior",
    "parent_version_id": 123,
    "project_source": "REGULAR"
  }'
```

```python
# parent_version_id chains this edit onto a previous version
result = await client.apply_copilot(
    project_uuid,
    "DSC_0001.JPEG",
    "brighten the interior",
    parent_version_id=123,
)
next_version_id = result.version_id  # e.g. 124
```

```typescript
// parentVersionId chains this edit onto a previous version
const result = await client.applyCopilot(
  projectUuid,
  'DSC_0001.JPEG',
  'brighten the interior',
  { parentVersionId: 123 }
);
const nextVersionId = result.versionId; // e.g. 124
```

```go
import imagen "github.com/imagenai/imagen-ai-sdk/sdks/go"

// ParentVersionID chains this edit onto a previous version
result, _ := client.Copilot(ctx, projectUUID, "DSC_0001.JPEG", imagen.CopilotRequest{
    Instruction:     "brighten the interior",
    ParentVersionID: 123,
    ProjectSource:   imagen.ProjectSourceRegular,
})
fmt.Println("next version:", result.VersionID) // e.g. 124
```

```java
import java.net.URI;

var body = """
    {
        "instruction": "brighten the interior",
        "parent_version_id": 123,
        "project_source": "REGULAR"
    }
    """;
var request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.imagen-ai.com/v1/projects/" + projectUuid + "/images/DSC_0001.JPEG/copilot"))
    .header("x-api-key", System.getenv("IMAGEN_API_KEY"))
    .header("Content-Type", "application/json")
    .POST(HttpRequest.BodyPublishers.ofString(body))
    .build();
var response = HttpClient.newHttpClient()
    .send(request, HttpResponse.BodyHandlers.ofString());
```

```ruby
require 'net/http'
require 'json'
require 'uri'

uri = URI("https://api.imagen-ai.com/v1/projects/#{project_uuid}/images/DSC_0001.JPEG/copilot")
req = Net::HTTP::Post.new(uri)
req['x-api-key'] = ENV['IMAGEN_API_KEY']
req['Content-Type'] = 'application/json'
req.body = {
  instruction: 'brighten the interior',
  parent_version_id: 123,
  project_source: 'REGULAR',
}.to_json

res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
next_version_id = JSON.parse(res.body)['version_id']
```

```php
<?php
$url = 'https://api.imagen-ai.com/v1/projects/' . $projectUuid . '/images/DSC_0001.JPEG/copilot';
$ch = curl_init($url);
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_POST => true,
  CURLOPT_HTTPHEADER => [
    'x-api-key: ' . getenv('IMAGEN_API_KEY'),
    'Content-Type: application/json',
  ],
  CURLOPT_POSTFIELDS => json_encode([
    'instruction' => 'brighten the interior',
    'parent_version_id' => 123,
    'project_source' => 'REGULAR',
  ]),
]);
$response = curl_exec($ch);
curl_close($ch);
$next_version_id = json_decode($response, true)['version_id'];
```

```csharp
using System.Net.Http;
using System.Text;
using System.Text.Json;

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key",
    Environment.GetEnvironmentVariable("IMAGEN_API_KEY"));

var payload = JsonSerializer.Serialize(new {
    instruction = "brighten the interior",
    parent_version_id = 123,
    project_source = "REGULAR",
});
var content = new StringContent(payload, Encoding.UTF8, "application/json");
var response = await client.PostAsync(
    $"https://api.imagen-ai.com/v1/projects/{projectUuid}/images/DSC_0001.JPEG/copilot", content);
```

### Preset enhancement

`POST .../images/{filename}/enhance` applies a preset enhancement to a single
image instead of a free-text instruction. It mirrors the `/copilot` call shape
and also returns a new version. Use it when you want a fixed enhancement rather
than a prompt.

## 3. List available AI tools

List the AI enhancement (preset) tools available for this project - the same presets the `/enhance` endpoint applies.

`GET /v1/projects/PROJECT_UUID/ai-tools`

```curl
curl 'https://api.imagen-ai.com/v1/projects/$PROJECT_UUID/ai-tools' \
  --header 'x-api-key: $IMAGEN_API_KEY'
```

```python
# Export once before any Copilot call - required.
await client.export_project(project_uuid)

tools = await client.get_ai_tools(project_uuid)
for t in tools.prompts:
    print(t.enhancement_type, t.label)
```

```typescript
// Export once before any Copilot call - required.
await client.exportProject(projectUuid);

const tools = await client.getAiTools(projectUuid);
for (const t of tools.prompts) {
  console.log(t.enhancementType, t.label);
}
```

```go
import imagen "github.com/imagenai/imagen-ai-sdk/sdks/go"

// Export once before any Copilot call - required.
if err := client.ExportAndWait(ctx, projectUUID, nil); err != nil {
    log.Fatal(err)
}

tools, _ := client.GetAITools(ctx, projectUUID, imagen.ProjectSourceRegular)
for _, t := range tools.Prompts {
    fmt.Println(t.EnhancementType, t.Label)
}
```

```java
import java.net.URI;

var request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.imagen-ai.com/v1/projects/" + projectUuid + "/ai-tools"))
    .header("x-api-key", System.getenv("IMAGEN_API_KEY"))
    .GET()
    .build();
var response = HttpClient.newHttpClient()
    .send(request, HttpResponse.BodyHandlers.ofString());
```

```ruby
require 'net/http'
require 'json'
require 'uri'

uri = URI("https://api.imagen-ai.com/v1/projects/#{project_uuid}/ai-tools")
req = Net::HTTP::Get.new(uri)
req['x-api-key'] = ENV['IMAGEN_API_KEY']

res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
tools = JSON.parse(res.body)
```

```php
<?php
$ch = curl_init('https://api.imagen-ai.com/v1/projects/' . $projectUuid . '/ai-tools');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_HTTPHEADER => ['x-api-key: ' . getenv('IMAGEN_API_KEY')],
]);
$response = curl_exec($ch);
curl_close($ch);
$tools = json_decode($response, true);
```

```csharp
using System.Net.Http;

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key",
    Environment.GetEnvironmentVariable("IMAGEN_API_KEY"));

var response = await client.GetAsync(
    $"https://api.imagen-ai.com/v1/projects/{projectUuid}/ai-tools");
var json = await response.Content.ReadAsStringAsync();
```

The response's `prompts` array holds each tool's `enhancement_type` (use it as the `tool_id` for `/enhance`), `label`, and `enabled_for_batch` flag.

## 4. Reset an image

Discard all Copilot edits on a single image and return it to its post-edit state.

`DELETE /v1/projects/PROJECT_UUID/images/FILENAME/copilot`

```curl
curl -X DELETE 'https://api.imagen-ai.com/v1/projects/$PROJECT_UUID/images/DSC_0001.JPEG/copilot' \
  --header 'x-api-key: $IMAGEN_API_KEY'
```

```python
await client.reset_copilot(project_uuid, "DSC_0001.JPEG")
```

```typescript
await client.resetCopilot(projectUuid, 'DSC_0001.JPEG');
```

```go
import imagen "github.com/imagenai/imagen-ai-sdk/sdks/go"

err := client.ResetCopilot(ctx, projectUUID, "DSC_0001.JPEG", imagen.ProjectSourceRegular)
if err != nil {
    log.Fatal(err)
}
```

```java
import java.net.URI;

var request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.imagen-ai.com/v1/projects/" + projectUuid + "/images/DSC_0001.JPEG/copilot"))
    .header("x-api-key", System.getenv("IMAGEN_API_KEY"))
    .DELETE()
    .build();
var response = HttpClient.newHttpClient()
    .send(request, HttpResponse.BodyHandlers.ofString());
```

```ruby
require 'net/http'
require 'uri'

uri = URI("https://api.imagen-ai.com/v1/projects/#{project_uuid}/images/DSC_0001.JPEG/copilot")
req = Net::HTTP::Delete.new(uri)
req['x-api-key'] = ENV['IMAGEN_API_KEY']

Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
```

```php
<?php
$url = 'https://api.imagen-ai.com/v1/projects/' . $projectUuid . '/images/DSC_0001.JPEG/copilot';
$ch = curl_init($url);
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_CUSTOMREQUEST => 'DELETE',
  CURLOPT_HTTPHEADER => ['x-api-key: ' . getenv('IMAGEN_API_KEY')],
]);
curl_exec($ch);
curl_close($ch);
```

```csharp
using System.Net.Http;

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key",
    Environment.GetEnvironmentVariable("IMAGEN_API_KEY"));

var response = await client.DeleteAsync(
    $"https://api.imagen-ai.com/v1/projects/{projectUuid}/images/DSC_0001.JPEG/copilot");
```

## 5. Finalize

Once you're satisfied with all Copilot edits across the project, call `/finalize`
to lock them in and prepare the output for download.

`POST /v1/projects/PROJECT_UUID/finalize`

```curl
curl -X POST 'https://api.imagen-ai.com/v1/projects/$PROJECT_UUID/finalize' \
  --header 'x-api-key: $IMAGEN_API_KEY'
```

```python
result = await client.finalize_project(project_uuid)
for f in result.files_list:
    print(f.file_name, f.download_link)
```

```typescript
const links = await client.finalizeProject(projectUuid);
// links is an array of final (upscaled) download URLs
```

```go
import imagen "github.com/imagenai/imagen-ai-sdk/sdks/go"

result, _ := client.Finalize(ctx, projectUUID, imagen.ProjectSourceRegular)
for _, f := range result.FilesList {
    fmt.Println(f.FileName, f.DownloadLink)
}
```

```java
import java.net.URI;

var request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.imagen-ai.com/v1/projects/" + projectUuid + "/finalize"))
    .header("x-api-key", System.getenv("IMAGEN_API_KEY"))
    .POST(HttpRequest.BodyPublishers.noBody())
    .build();
var response = HttpClient.newHttpClient()
    .send(request, HttpResponse.BodyHandlers.ofString());
```

```ruby
require 'net/http'
require 'uri'

uri = URI("https://api.imagen-ai.com/v1/projects/#{project_uuid}/finalize")
req = Net::HTTP::Post.new(uri)
req['x-api-key'] = ENV['IMAGEN_API_KEY']

Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
```

```php
<?php
$ch = curl_init('https://api.imagen-ai.com/v1/projects/' . $projectUuid . '/finalize');
curl_setopt_array($ch, [
  CURLOPT_RETURNTRANSFER => true,
  CURLOPT_POST => true,
  CURLOPT_HTTPHEADER => ['x-api-key: ' . getenv('IMAGEN_API_KEY')],
]);
curl_exec($ch);
curl_close($ch);
```

```csharp
using System.Net.Http;

using var client = new HttpClient();
client.DefaultRequestHeaders.Add("x-api-key",
    Environment.GetEnvironmentVariable("IMAGEN_API_KEY"));

var response = await client.PostAsync(
    $"https://api.imagen-ai.com/v1/projects/{projectUuid}/finalize", null);
```

After finalizing, use the same download endpoint as your editing mode to retrieve
the output files. Use [Quickstart](/docs/quickstart) for profile-based projects, or
[Smart Editing](/docs/reference/smart-editing) for I2I projects.

> **Human revision is not yet in the API** Requesting an Imagen expert to review and re-edit a photo is available in the web app but is not yet supported via the API.
