> ## Documentation Index
> Fetch the complete documentation index at: https://mintlify.com/bytedance/deer-flow/llms.txt
> Use this file to discover all available pages before exploring further.

# Artifacts API

> Access and download thread artifacts and generated files

## Overview

The Artifacts API provides endpoints to retrieve files generated by AI agents or uploaded by users. It supports various file types including text, HTML, binary files, and files within .skill archives.

## Get Artifact File

<Card title="GET /api/threads/{thread_id}/artifacts/{path}" icon="file">
  Retrieve an artifact file generated by the AI agent or uploaded by the user
</Card>

### Path Parameters

<ParamField path="thread_id" type="string" required>
  The thread ID
</ParamField>

<ParamField path="path" type="string" required>
  The artifact path with virtual prefix (e.g., `mnt/user-data/outputs/file.txt`)
</ParamField>

### Query Parameters

<ParamField query="download" type="boolean" default="false">
  If true, returns file as attachment for download. Otherwise, files are displayed inline.
</ParamField>

### Response

The response content type depends on the file type:

* **HTML files** (`.html`): Rendered as HTML (`text/html`)
* **Text files**: Returned as plain text with appropriate MIME type
* **Binary files**: Returned with appropriate MIME type

### Example Requests

#### View HTML File

```bash theme={null}
curl http://localhost:8001/api/threads/abc123/artifacts/mnt/user-data/outputs/index.html
```

Response: HTML content rendered in browser

#### View Text File

```bash theme={null}
curl http://localhost:8001/api/threads/abc123/artifacts/mnt/user-data/outputs/script.py
```

Response: Plain text with `text/x-python` MIME type

#### Download File

```bash theme={null}
curl "http://localhost:8001/api/threads/abc123/artifacts/mnt/user-data/outputs/data.csv?download=true" \
  -o data.csv
```

Response: File downloaded with `Content-Disposition: attachment` header

#### View Uploaded File

```bash theme={null}
curl http://localhost:8001/api/threads/abc123/artifacts/mnt/user-data/uploads/document.pdf
```

Response: PDF displayed inline in browser

### Error Responses

<ResponseField name="400" type="Bad Request">
  Path is not a file

  ```json theme={null}
  {
    "detail": "Path is not a file: mnt/user-data/outputs"
  }
  ```
</ResponseField>

<ResponseField name="403" type="Forbidden">
  Access denied (path traversal attempt)

  ```json theme={null}
  {
    "detail": "Access denied"
  }
  ```
</ResponseField>

<ResponseField name="404" type="Not Found">
  Artifact not found

  ```json theme={null}
  {
    "detail": "Artifact not found: mnt/user-data/outputs/missing.txt"
  }
  ```
</ResponseField>

***

## .skill Archive Files

<Card title="GET /api/threads/{thread_id}/artifacts/{skill_path}.skill/{internal_path}" icon="file-zipper">
  Retrieve a file from within a .skill archive without extracting
</Card>

### Path Format

To access files inside .skill archives, use the format:

```
/api/threads/{thread_id}/artifacts/{path/to/file}.skill/{internal_path}
```

### Example Requests

#### View SKILL.md from Archive

```bash theme={null}
curl http://localhost:8001/api/threads/abc123/artifacts/mnt/user-data/outputs/my-skill.skill/SKILL.md
```

Response: Markdown content from inside the ZIP archive

#### View Script from Archive

```bash theme={null}
curl http://localhost:8001/api/threads/abc123/artifacts/mnt/user-data/outputs/my-skill.skill/scripts/install.sh
```

Response: Script content from `scripts/install.sh` inside the archive

### How It Works

1. The API detects `.skill/` in the path
2. Splits the path into archive path and internal path
3. Opens the .skill file (ZIP archive)
4. Extracts the requested file without extracting the entire archive
5. Returns the file content with appropriate MIME type
6. Caches for 5 minutes to avoid repeated ZIP extraction

### Error Responses

<ResponseField name="404" type="Not Found">
  Archive or file not found

  ```json theme={null}
  {
    "detail": "File 'README.md' not found in skill archive"
  }
  ```
</ResponseField>

***

## Virtual Paths

DeerFlow uses virtual paths to organize files:

### Outputs Directory

Files generated by AI agents:

```
/mnt/user-data/outputs/
```

Example paths:

* `mnt/user-data/outputs/index.html` - Generated web page
* `mnt/user-data/outputs/script.py` - Generated Python script
* `mnt/user-data/outputs/my-skill.skill` - Packaged skill file

### Uploads Directory

Files uploaded by users:

```
/mnt/user-data/uploads/
```

Example paths:

* `mnt/user-data/uploads/document.pdf` - Uploaded PDF
* `mnt/user-data/uploads/document.md` - Auto-converted markdown
* `mnt/user-data/uploads/image.png` - Uploaded image

### Path Resolution

The API resolves virtual paths to actual filesystem paths:

```
mnt/user-data/outputs/file.txt
→ backend/sandbox/threads/{thread_id}/outputs/file.txt

mnt/user-data/uploads/file.pdf
→ backend/sandbox/threads/{thread_id}/uploads/file.pdf
```

***

## Content Types

The API automatically detects and sets appropriate MIME types:

### Text Files

* `.txt` → `text/plain`
* `.md` → `text/markdown`
* `.py` → `text/x-python`
* `.js` → `text/javascript`
* `.json` → `application/json`
* `.yaml`, `.yml` → `application/x-yaml`

### Web Files

* `.html` → `text/html` (rendered in browser)
* `.css` → `text/css`
* `.js` → `text/javascript`

### Documents

* `.pdf` → `application/pdf`
* `.doc`, `.docx` → `application/vnd.openxmlformats-officedocument.wordprocessingml.document`
* `.xls`, `.xlsx` → `application/vnd.openxmlformats-officedocument.spreadsheetml.sheet`

### Images

* `.png` → `image/png`
* `.jpg`, `.jpeg` → `image/jpeg`
* `.gif` → `image/gif`
* `.svg` → `image/svg+xml`

### Archives

* `.zip` → `application/zip`
* `.tar.gz` → `application/gzip`

***

## Content Disposition

The API uses different `Content-Disposition` headers:

### Inline Display (Default)

```http theme={null}
Content-Disposition: inline; filename*=UTF-8''document.pdf
```

Files are displayed in the browser when possible.

### Force Download

With `?download=true`:

```http theme={null}
Content-Disposition: attachment; filename*=UTF-8''document.pdf
```

Forces file download instead of inline display.

***

## Security

### Path Traversal Protection

The API validates all paths to prevent directory traversal attacks:

* Paths must be within the thread's sandbox directory
* Attempts to access parent directories (`../`) are blocked
* Returns 403 Forbidden for unauthorized access attempts

### Filename Encoding

Filenames with special characters are properly encoded using RFC 5987:

```http theme={null}
Content-Disposition: inline; filename*=UTF-8''%E6%96%87%E4%BB%B6.txt
```

This ensures proper handling of:

* Unicode characters
* Spaces
* Special characters

***

## Use Cases

### Display Generated HTML

```html theme={null}
<!-- Embed generated HTML page -->
<iframe 
  src="http://localhost:8001/api/threads/abc123/artifacts/mnt/user-data/outputs/index.html"
  width="100%" 
  height="600">
</iframe>
```

### Download Generated File

```typescript theme={null}
async function downloadArtifact(threadId: string, path: string, filename: string) {
  const url = `http://localhost:8001/api/threads/${threadId}/artifacts/${path}?download=true`;
  
  const response = await fetch(url);
  const blob = await response.blob();
  
  // Create download link
  const link = document.createElement('a');
  link.href = URL.createObjectURL(blob);
  link.download = filename;
  link.click();
}

// Usage
downloadArtifact('abc123', 'mnt/user-data/outputs/report.pdf', 'report.pdf');
```

### View Artifact as Text

```typescript theme={null}
async function viewArtifactText(threadId: string, path: string) {
  const url = `http://localhost:8001/api/threads/${threadId}/artifacts/${path}`;
  const response = await fetch(url);
  const text = await response.text();
  return text;
}

// Usage
const code = await viewArtifactText('abc123', 'mnt/user-data/outputs/script.py');
console.log(code);
```

### List Artifact URLs from Upload Response

```typescript theme={null}
// After uploading files
const uploadResponse = await uploadFiles(threadId, files);

// Get artifact URLs
const artifactUrls = uploadResponse.files.map(file => ({
  filename: file.filename,
  url: `http://localhost:8001${file.artifact_url}`,
  downloadUrl: `http://localhost:8001${file.artifact_url}?download=true`
}));
```

### Preview File from .skill Archive

```typescript theme={null}
async function previewSkillFile(threadId: string, skillPath: string, internalPath: string) {
  const url = `http://localhost:8001/api/threads/${threadId}/artifacts/${skillPath}/${internalPath}`;
  const response = await fetch(url);
  const content = await response.text();
  return content;
}

// Usage
const skillMd = await previewSkillFile(
  'abc123',
  'mnt/user-data/outputs/my-skill.skill',
  'SKILL.md'
);
```

***

## Related

<CardGroup cols={2}>
  <Card title="Uploads API" icon="upload" href="/api/gateway/uploads">
    Upload files to threads
  </Card>

  <Card title="Gateway Overview" icon="book" href="/api/gateway/overview">
    Learn about the Gateway API
  </Card>
</CardGroup>
