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

# Files

> Let any model read, write, edit, and list workspace files

Beta

> [!NOTE]
>
> **Beta**
>
> Server tools are currently in beta. The API and behavior may change.
>
> The files tool and the Files API are available on the global endpoint (`openrouter.ai`) only. Requests through the [in-region endpoints](https://openrouter.ai/docs/guides/features/in-region-routing.md) (`eu.openrouter.ai`, `us.openrouter.ai`) are rejected; the Files API returns a `403` there.

The `openrouter:files` server tool lets a model read, write, edit, and list text files in your workspace via the OpenRouter Files API. When the model needs file access (reading an uploaded document, saving output, or applying a targeted edit), it calls the tool and OpenRouter executes the operation server-side.

> [!WARNING]
>
> **The tool sees one workspace: your key's**
>
> The files it can list, read, write, and edit are the ones in the workspace your API key is scoped to. A key with no workspace gets your default workspace, not necessarily the one you uploaded through in the dashboard. If the model reports a file it should be able to see as missing, check which workspace the key belongs to first.

## Quick start

```typescript title="TypeScript" expandable lines theme={null}
const response = await fetch('https://openrouter.ai/api/v1/responses', {
  method: 'POST',
  headers: {
    Authorization: 'Bearer <OPENROUTER_API_KEY>',
    'Content-Type': 'application/json',
  },
  body: JSON.stringify({
    model: 'openai/gpt-5.2',
    input: 'List the files in my workspace and summarize notes.txt.',
    tools: [
      { type: 'openrouter:files' }
    ]
  }),
});

const data = await response.json();
const message = [...data.output].reverse().find((item: { type: string }) => item.type === 'message');
console.log(message?.content.find((part: { type: string; text?: string }) => part.type === 'output_text')?.text);
```

```python title="Python" expandable lines theme={null}
import requests

response = requests.post(
  "https://openrouter.ai/api/v1/responses",
  headers={
    "Authorization": f"Bearer <OPENROUTER_API_KEY>",
    "Content-Type": "application/json",
  },
  json={
    "model": "openai/gpt-5.2",
    "input": "List the files in my workspace and summarize notes.txt.",
    "tools": [
      {"type": "openrouter:files"}
    ]
  }
)

data = response.json()
message = next(item for item in reversed(data["output"]) if item["type"] == "message")
print(next(part["text"] for part in message["content"] if part["type"] == "output_text"))
```

```bash title="cURL" lines theme={null}
curl https://openrouter.ai/api/v1/responses \
  -H "Authorization: Bearer <OPENROUTER_API_KEY>" \
  -H "Content-Type: application/json" \
  -d '{
    "model": "openai/gpt-5.2",
    "input": "List the files in my workspace and summarize notes.txt.",
    "tools": [
      {"type": "openrouter:files"}
    ]
  }'
```

## Configuration

The files tool has no configuration options. Which workspace and files it can access is determined by your API key, so enabling the tool takes only its type:

```json lines theme={null}
{
  "type": "openrouter:files"
}
```

## Operations

The model generates the call arguments. Each call performs one operation:

| Operation | Description |
| - | - |
| `list` | List workspace files, optionally filtered by `filename_filter` |
| `read` | Read a file by `file_id` or `filename` |
| `write` | Create a new file from `filename` and `content` |
| `edit` | Replace `old_string` with `new_string` in a file |

### Call arguments

| Field | Type | Description |
| - | - | - |
| `operation` | string | The file operation to perform: `list`, `read`, `write`, or `edit` |
| `file_id` | string | Target file id (read/edit). Preferred over `filename` when known |
| `filename` | string | Target filename (read/edit lookup), or the filename for a new file (write). May include a folder path |
| `filename_filter` | string | list: only return files whose filename contains this substring |
| `content` | string | write: the full UTF-8 text content of the new file |
| `old_string` | string | edit: the exact text to replace (must match a single location) |
| `new_string` | string | edit: the replacement text |
| `new_filename` | string | edit: optional filename for the edited copy; defaults to the source filename |

> [!NOTE]
>
> **Edits are copy-on-write**
>
> Editing a file creates a new copy with a new `file_id`; the original file is left unchanged.

## Response

The tool returns `{ "result": ... }` on success with the operation's output (file listing, file content, or the new file's metadata), or `{ "error": "..." }` when the operation fails (for example, when a required field is missing or the target file isn't found). The model reads the error and can retry with corrected arguments.

Files created by `write` or `edit` are model-generated output, so they have `"downloadable": true` and can be downloaded through `GET /api/v1/files/{file_id}/content`. See [Download rules](https://openrouter.ai/docs/guides/features/files-api.md#download-rules).

## Pricing

There's currently no separate charge for the files tool; you pay only for standard token usage.

## Next steps

* [Server Tools Overview](https://openrouter.ai/docs/guides/features/server-tools.md): Learn about server tools
* [Files API](https://openrouter.ai/docs/guides/features/files-api.md): Upload and manage workspace files
* [Containers](https://openrouter.ai/docs/guides/features/containers.md): How sandbox containers work
* [Apply Patch](https://openrouter.ai/docs/guides/features/server-tools/apply-patch.md): Let models propose file edits as V4A diffs
* [Tool Calling](https://openrouter.ai/docs/guides/features/tool-calling.md): Learn about user-defined tool calling
