> For a complete page index of the Captain API documentation, fetch https://docs.captain.dev/llms.txt?excludeSpec=true

# Copy Collection

POST https://api.captain.dev/v2/collections/{collection_name}/copy
Content-Type: application/json

Clone metadata, documents, and vectors under a new name. Instant regardless of size.

Reference: https://docs.captain.dev/reference/collections/copy

## Request

### Path parameters

- `collection_name` (string, required)

### Body (application/json)

This endpoint expects a CollectionCopyRequest.

- `target_name` (string, required) — Name for the copy. Must be unique within the organization and environment. Same rules as creating a collection: 3-63 characters, alphanumeric start and end, letters, numbers, hyphens and underscores only.
- `include_graph` (boolean, optional, default: true) — Copy the collection's chunk relations and chunk metadata along with its documents and vectors. Defaults to true so a copy is a faithful original; set false to copy documents and vectors only.

## Response

### 200

Successful Response

- `success` (boolean, required)
- `message` (string, required)
- `source_collection` (string, required) — Name of the collection copied from.
- `collection_name` (string, required) — Name of the new copy.
- `collection_id` (string, required) — ID of the new copy.
- `documents_copied` (integer, required) — Number of documents cloned.
- `namespaces_copied` (integer, required) — Number of Turbopuffer namespaces copied (text plus any media).
- `files_copied` (integer, optional, default: 0) — Number of files cloned.
- `relations_copied` (integer, optional, default: 0) — Number of chunk relations cloned. Counts ROWS, not distinct edges: duplicate (source, target, type) triples in the source are reproduced faithfully.
- `chunk_metadata_copied` (integer, optional, default: 0) — Number of chunk metadata rows cloned.
- `relations_unresolved` (integer, optional, default: 0) — Relations copied whose target document could not be remapped into the new collection, so their target_document_id is null. Usually these are edges already broken in the source (the target document was deleted, or the id never matched a document); if the source was being indexed while the copy ran, a freshly created edge can also land here. The copy reproduces the edge rather than writing a pointer that resolves to nothing.

## Errors

### 404 Not Found Error

Source collection not found

- `error` (string, required)
- `message` (string, required)
- `details` (ErrorResponseV2Details, optional, nullable)
- `path` (string, optional, nullable)
- `success` (boolean, optional, default: false)

### 409 Conflict Error

target_name is already in use

- `error` (string, required)
- `message` (string, required)
- `details` (ErrorResponseV2Details, optional, nullable)
- `path` (string, optional, nullable)
- `success` (boolean, optional, default: false)

### 422 Unprocessable Entity Error

target_name is missing or fails the name rules

- `error` (string, required)
- `message` (string, required)
- `details` (ErrorResponseV2Details, optional, nullable)
- `path` (string, optional, nullable)
- `success` (boolean, optional, default: false)

## Types

### ErrorResponseV2Details

## Examples

**Request**

```json
{
  "target_name": "my_documents_v2"
}
```

**Response**

```json
{
  "success": true,
  "message": "Copied 'my_documents' to 'my_documents_v2' (142 documents)",
  "source_collection": "my_documents",
  "collection_name": "my_documents_v2",
  "collection_id": "01931f4e-8c2a-7c31-9f5e-2b7a1d3e4f60",
  "documents_copied": 142,
  "namespaces_copied": 2,
  "files_copied": 142,
  "relations_copied": 356,
  "chunk_metadata_copied": 89,
  "relations_unresolved": 0
}
```

**SDK Code**

```python Python REST
import requests

BASE_URL = "https://api.captain.dev"
API_KEY = "your_api_key"
COLLECTION_NAME = "my_documents"

headers = {
    "Authorization": f"Bearer {API_KEY}",
    "Content-Type": "application/json"
}

response = requests.post(
    f"{BASE_URL}/v2/collections/{COLLECTION_NAME}/copy",
    headers=headers,
    json={"target_name": "my_documents_v2"},
    timeout=120.0
)

if response.status_code == 200:
    data = response.json()
    print(f"Created {data['collection_name']} ({data['documents_copied']} documents)")
elif response.status_code == 409:
    print("That name is taken. Choose a different target_name.")
else:
    print(f"Error {response.status_code}: {response.text}")
```

```typescript TypeScript REST
const BASE_URL = "https://api.captain.dev";
const API_KEY = "your_api_key";
const COLLECTION_NAME = "my_documents";

const response = await fetch(
  `${BASE_URL}/v2/collections/${COLLECTION_NAME}/copy`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${API_KEY}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({ target_name: "my_documents_v2" }),
  }
);

if (response.ok) {
  const data = await response.json();
  console.log(`Created ${data.collection_name} (${data.documents_copied} documents)`);
} else if (response.status === 409) {
  console.log("That name is taken. Choose a different target_name.");
}
```