# REST API

**All responses are JSON.** Every request must carry an `Authorization: Bearer $DONUT_API_KEY` header — see [Authentication](/docs/authentication). Set the env var in your shell once and every example below will pick it up.

Total endpoints: 28 across 6 tags.

## Profiles

Manage isolated browser profiles — create, list, update, delete, launch, kill, drive.

### GET /v1/profiles

Returns every profile in the local install.

**curl**

```bash
curl -sS -X GET http://127.0.0.1:10108/v1/profiles \
  -H "Authorization: Bearer $DONUT_API_KEY"
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/profiles", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
  },
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.get(
    "http://127.0.0.1:10108/v1/profiles",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$response = Invoke-RestMethod -Method GET -Uri "http://127.0.0.1:10108/v1/profiles" `
    -Headers $headers

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
{
  "profiles": [
    {
      "id": "ce490dd0-02fe-4be5-b91d-fedec7550b28",
      "name": "Work · Chromium",
      "browser": "wayfern",
      "version": "147.0.7727.138",
      "release_type": "stable",
      "group_id": "75f2b42f-8c94-4291-8af7-7a3d79122507",
      "proxy_id": null,
      "vpn_id": null,
      "tags": [],
      "is_running": true,
      "process_id": 29300,
      "last_launch": 1779106515,
      "camoufox_config": null,
      "launch_hook": null,
      "proxy_bypass_rules": []
    },
    {
      "id": "c20221fa-be36-485d-a4e1-5537254fa863",
      "name": "Personal · Firefox",
      "browser": "camoufox",
      "version": "v150.0.2-beta.25",
      "release_type": "stable",
      "group_id": null,
      "proxy_id": null,
      "vpn_id": null,
      "tags": [
        "personal"
      ],
      "is_running": false,
      "process_id": null,
      "last_launch": 1779226206,
      "camoufox_config": {},
      "launch_hook": null,
      "proxy_bypass_rules": []
    }
  ]
}
```

### POST /v1/profiles

Both browser engines need their own config object. Pass `wayfern_config: {}` and `camoufox_config: {}` for sensible defaults.

**curl**

```bash
curl -sS -X POST http://127.0.0.1:10108/v1/profiles \
  -H "Authorization: Bearer $DONUT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "name": "client-1",
      "browser": "chromium",
      "version": "latest",
      "proxy_id": "c5617755-0709-4820-832a-6b97a0a24f3c",
      "tags": [
        "client-1",
        "prod"
      ],
      "wayfern_config": {},
      "camoufox_config": {}
    }'
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/profiles", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "client-1",
    "browser": "chromium",
    "version": "latest",
    "proxy_id": "c5617755-0709-4820-832a-6b97a0a24f3c",
    "tags": [
      "client-1",
      "prod"
    ],
    "wayfern_config": {},
    "camoufox_config": {}
  }),
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.post(
    "http://127.0.0.1:10108/v1/profiles",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    json={
      "name": "client-1",
      "browser": "chromium",
      "version": "latest",
      "proxy_id": "c5617755-0709-4820-832a-6b97a0a24f3c",
      "tags": [
        "client-1",
        "prod"
      ],
      "wayfern_config": {},
      "camoufox_config": {}
    },
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$body = @'
{
  "name": "client-1",
  "browser": "chromium",
  "version": "latest",
  "proxy_id": "c5617755-0709-4820-832a-6b97a0a24f3c",
  "tags": [
    "client-1",
    "prod"
  ],
  "wayfern_config": {},
  "camoufox_config": {}
}
'@

$response = Invoke-RestMethod -Method POST -Uri "http://127.0.0.1:10108/v1/profiles" `
    -Headers $headers -ContentType "application/json" -Body $body

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
{
  "profile": {
    "id": "prf_01J8...",
    "name": "client-1",
    "browser": "chromium",
    "version": "latest",
    "release_type": "stable",
    "group_id": null,
    "proxy_id": "c5617755-0709-4820-832a-6b97a0a24f3c",
    "vpn_id": null,
    "tags": [
      "client-1",
      "prod"
    ],
    "is_running": false,
    "process_id": null,
    "last_launch": null,
    "camoufox_config": {},
    "launch_hook": null,
    "proxy_bypass_rules": []
  }
}
```

### GET /v1/profiles/{id}

Fetches the full profile object by ID.

**curl**

```bash
curl -sS -X GET http://127.0.0.1:10108/v1/profiles/{id} \
  -H "Authorization: Bearer $DONUT_API_KEY"
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/profiles/{id}", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
  },
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.get(
    "http://127.0.0.1:10108/v1/profiles/{id}",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$response = Invoke-RestMethod -Method GET -Uri "http://127.0.0.1:10108/v1/profiles/{id}" `
    -Headers $headers

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
{
  "profile": {
    "id": "ce490dd0-02fe-4be5-b91d-fedec7550b28",
    "name": "Work · Chromium",
    "browser": "wayfern",
    "version": "147.0.7727.138",
    "release_type": "stable",
    "group_id": "75f2b42f-8c94-4291-8af7-7a3d79122507",
    "proxy_id": null,
    "vpn_id": null,
    "tags": [],
    "is_running": true,
    "process_id": 29300,
    "last_launch": 1779106515,
    "camoufox_config": null,
    "launch_hook": null,
    "proxy_bypass_rules": []
  }
}
```

### PUT /v1/profiles/{id}

Any subset of fields can be sent. `camoufox_config` is required by the spec; pass the current value if you don't want to change it.

**curl**

```bash
curl -sS -X PUT http://127.0.0.1:10108/v1/profiles/{id} \
  -H "Authorization: Bearer $DONUT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "name": "Work · Chromium — renamed",
      "proxy_id": "c5617755-0709-4820-832a-6b97a0a24f3c",
      "tags": [
        "work",
        "client-1"
      ],
      "camoufox_config": {}
    }'
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/profiles/{id}", {
  method: "PUT",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "Work · Chromium — renamed",
    "proxy_id": "c5617755-0709-4820-832a-6b97a0a24f3c",
    "tags": [
      "work",
      "client-1"
    ],
    "camoufox_config": {}
  }),
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.put(
    "http://127.0.0.1:10108/v1/profiles/{id}",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    json={
      "name": "Work · Chromium — renamed",
      "proxy_id": "c5617755-0709-4820-832a-6b97a0a24f3c",
      "tags": [
        "work",
        "client-1"
      ],
      "camoufox_config": {}
    },
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$body = @'
{
  "name": "Work · Chromium — renamed",
  "proxy_id": "c5617755-0709-4820-832a-6b97a0a24f3c",
  "tags": [
    "work",
    "client-1"
  ],
  "camoufox_config": {}
}
'@

$response = Invoke-RestMethod -Method PUT -Uri "http://127.0.0.1:10108/v1/profiles/{id}" `
    -Headers $headers -ContentType "application/json" -Body $body

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
{
  "profile": {
    "id": "...",
    "name": "Work · Chromium — renamed",
    "...": "..."
  }
}
```

### DELETE /v1/profiles/{id}

Hard delete. The profile data on disk is removed.

**curl**

```bash
curl -sS -X DELETE http://127.0.0.1:10108/v1/profiles/{id} \
  -H "Authorization: Bearer $DONUT_API_KEY"
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/profiles/{id}", {
  method: "DELETE",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
  },
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.delete(
    "http://127.0.0.1:10108/v1/profiles/{id}",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$response = Invoke-RestMethod -Method DELETE -Uri "http://127.0.0.1:10108/v1/profiles/{id}" `
    -Headers $headers

$response | ConvertTo-Json -Depth 10
```

**Response**

```http
204 No Content
```

### POST /v1/profiles/{id}/run — Pro

Spawns the browser process for the profile and returns the CDP port. Optionally headless and/or opening at a specific URL.

**curl**

```bash
curl -sS -X POST http://127.0.0.1:10108/v1/profiles/{id}/run \
  -H "Authorization: Bearer $DONUT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "url": "https://whoer.net",
      "headless": false
    }'
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/profiles/{id}/run", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "url": "https://whoer.net",
    "headless": false
  }),
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.post(
    "http://127.0.0.1:10108/v1/profiles/{id}/run",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    json={
      "url": "https://whoer.net",
      "headless": False
    },
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$body = @'
{
  "url": "https://whoer.net",
  "headless": false
}
'@

$response = Invoke-RestMethod -Method POST -Uri "http://127.0.0.1:10108/v1/profiles/{id}/run" `
    -Headers $headers -ContentType "application/json" -Body $body

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
{
  "cdp_port": 9222,
  "process_id": 41218
}
```

> Without an active Pro subscription this endpoint returns HTTP 402 Payment Required.

### POST /v1/profiles/{id}/kill

Terminates the browser process for the profile.

**curl**

```bash
curl -sS -X POST http://127.0.0.1:10108/v1/profiles/{id}/kill \
  -H "Authorization: Bearer $DONUT_API_KEY"
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/profiles/{id}/kill", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
  },
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.post(
    "http://127.0.0.1:10108/v1/profiles/{id}/kill",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$response = Invoke-RestMethod -Method POST -Uri "http://127.0.0.1:10108/v1/profiles/{id}/kill" `
    -Headers $headers

$response | ConvertTo-Json -Depth 10
```

**Response**

```http
204 No Content
```

### POST /v1/profiles/{id}/open-url — Pro

Opens the given URL as a new tab in a profile that's already running.

**curl**

```bash
curl -sS -X POST http://127.0.0.1:10108/v1/profiles/{id}/open-url \
  -H "Authorization: Bearer $DONUT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "url": "https://news.ycombinator.com"
    }'
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/profiles/{id}/open-url", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "url": "https://news.ycombinator.com"
  }),
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.post(
    "http://127.0.0.1:10108/v1/profiles/{id}/open-url",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    json={
      "url": "https://news.ycombinator.com"
    },
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$body = @'
{
  "url": "https://news.ycombinator.com"
}
'@

$response = Invoke-RestMethod -Method POST -Uri "http://127.0.0.1:10108/v1/profiles/{id}/open-url" `
    -Headers $headers -ContentType "application/json" -Body $body

$response | ConvertTo-Json -Depth 10
```

**Response**

```http
200 OK
```

> Without an active Pro subscription this endpoint returns HTTP 402 Payment Required.

## Groups

Organize profiles into named groups for bulk actions.

### GET /v1/groups

Every group, with its current profile count.

**curl**

```bash
curl -sS -X GET http://127.0.0.1:10108/v1/groups \
  -H "Authorization: Bearer $DONUT_API_KEY"
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/groups", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
  },
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.get(
    "http://127.0.0.1:10108/v1/groups",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$response = Invoke-RestMethod -Method GET -Uri "http://127.0.0.1:10108/v1/groups" `
    -Headers $headers

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
[
  {
    "id": "75f2b42f-8c94-4291-8af7-7a3d79122507",
    "name": "Work",
    "profile_count": 12
  },
  {
    "id": "bfda155d-0c04-4fc2-ab62-30651557a510",
    "name": "Personal",
    "profile_count": 3
  }
]
```

### POST /v1/groups

Create a named group profiles can be assigned to.

**curl**

```bash
curl -sS -X POST http://127.0.0.1:10108/v1/groups \
  -H "Authorization: Bearer $DONUT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "name": "Client – Acme"
    }'
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/groups", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "Client – Acme"
  }),
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.post(
    "http://127.0.0.1:10108/v1/groups",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    json={
      "name": "Client – Acme"
    },
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$body = @'
{
  "name": "Client – Acme"
}
'@

$response = Invoke-RestMethod -Method POST -Uri "http://127.0.0.1:10108/v1/groups" `
    -Headers $headers -ContentType "application/json" -Body $body

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
{
  "id": "grp_01J8...",
  "name": "Client – Acme",
  "profile_count": 0
}
```

### GET /v1/groups/{id}

Fetches a single group by ID.

**curl**

```bash
curl -sS -X GET http://127.0.0.1:10108/v1/groups/{id} \
  -H "Authorization: Bearer $DONUT_API_KEY"
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/groups/{id}", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
  },
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.get(
    "http://127.0.0.1:10108/v1/groups/{id}",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$response = Invoke-RestMethod -Method GET -Uri "http://127.0.0.1:10108/v1/groups/{id}" `
    -Headers $headers

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
{
  "id": "bfda155d-0c04-4fc2-ab62-30651557a510",
  "name": "Personal",
  "profile_count": 3
}
```

### PUT /v1/groups/{id}

Updates the group name.

**curl**

```bash
curl -sS -X PUT http://127.0.0.1:10108/v1/groups/{id} \
  -H "Authorization: Bearer $DONUT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "name": "Client – Acme (2026)"
    }'
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/groups/{id}", {
  method: "PUT",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "Client – Acme (2026)"
  }),
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.put(
    "http://127.0.0.1:10108/v1/groups/{id}",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    json={
      "name": "Client – Acme (2026)"
    },
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$body = @'
{
  "name": "Client – Acme (2026)"
}
'@

$response = Invoke-RestMethod -Method PUT -Uri "http://127.0.0.1:10108/v1/groups/{id}" `
    -Headers $headers -ContentType "application/json" -Body $body

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
{
  "id": "grp_01J8...",
  "name": "Client – Acme (2026)",
  "profile_count": 8
}
```

### DELETE /v1/groups/{id}

Profiles assigned to the group are not deleted — their `group_id` is set to null.

**curl**

```bash
curl -sS -X DELETE http://127.0.0.1:10108/v1/groups/{id} \
  -H "Authorization: Bearer $DONUT_API_KEY"
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/groups/{id}", {
  method: "DELETE",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
  },
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.delete(
    "http://127.0.0.1:10108/v1/groups/{id}",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$response = Invoke-RestMethod -Method DELETE -Uri "http://127.0.0.1:10108/v1/groups/{id}" `
    -Headers $headers

$response | ConvertTo-Json -Depth 10
```

**Response**

```http
204 No Content
```

## Tags

Flat list of every tag used across your profiles.

### GET /v1/tags

Flat deduplicated list of every tag string used across your profiles.

**curl**

```bash
curl -sS -X GET http://127.0.0.1:10108/v1/tags \
  -H "Authorization: Bearer $DONUT_API_KEY"
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/tags", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
  },
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.get(
    "http://127.0.0.1:10108/v1/tags",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$response = Invoke-RestMethod -Method GET -Uri "http://127.0.0.1:10108/v1/tags" `
    -Headers $headers

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
[
  "client-1",
  "prod",
  "personal",
  "burner"
]
```

## Proxies

HTTP, HTTPS, SOCKS4, SOCKS5 proxy definitions. Attach to a profile via `proxy_id`.

### GET /v1/proxies

Every proxy definition stored locally.

**curl**

```bash
curl -sS -X GET http://127.0.0.1:10108/v1/proxies \
  -H "Authorization: Bearer $DONUT_API_KEY"
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/proxies", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
  },
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.get(
    "http://127.0.0.1:10108/v1/proxies",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$response = Invoke-RestMethod -Method GET -Uri "http://127.0.0.1:10108/v1/proxies" `
    -Headers $headers

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
[
  {
    "id": "c5617755-0709-4820-832a-6b97a0a24f3c",
    "name": "Albania",
    "proxy_settings": {
      "proxy_type": "https",
      "host": "proxy.example.com",
      "port": 8080,
      "username": "user",
      "password": "secret"
    }
  }
]
```

### POST /v1/proxies

`proxy_type` ∈ `http` | `https` | `socks4` | `socks5`. `username`/`password` are optional for unauthenticated proxies.

**curl**

```bash
curl -sS -X POST http://127.0.0.1:10108/v1/proxies \
  -H "Authorization: Bearer $DONUT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "name": "us-residential",
      "proxy_settings": {
        "proxy_type": "socks5",
        "host": "proxy.example.com",
        "port": 1080,
        "username": "user",
        "password": "secret"
      }
    }'
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/proxies", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "us-residential",
    "proxy_settings": {
      "proxy_type": "socks5",
      "host": "proxy.example.com",
      "port": 1080,
      "username": "user",
      "password": "secret"
    }
  }),
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.post(
    "http://127.0.0.1:10108/v1/proxies",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    json={
      "name": "us-residential",
      "proxy_settings": {
        "proxy_type": "socks5",
        "host": "proxy.example.com",
        "port": 1080,
        "username": "user",
        "password": "secret"
      }
    },
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$body = @'
{
  "name": "us-residential",
  "proxy_settings": {
    "proxy_type": "socks5",
    "host": "proxy.example.com",
    "port": 1080,
    "username": "user",
    "password": "secret"
  }
}
'@

$response = Invoke-RestMethod -Method POST -Uri "http://127.0.0.1:10108/v1/proxies" `
    -Headers $headers -ContentType "application/json" -Body $body

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
{
  "id": "pxy_01J8...",
  "name": "us-residential",
  "proxy_settings": {
    "proxy_type": "socks5",
    "host": "proxy.example.com",
    "port": 1080,
    "username": "user",
    "password": "secret"
  }
}
```

### GET /v1/proxies/{id}

Returns the single proxy definition matching the ID.

**curl**

```bash
curl -sS -X GET http://127.0.0.1:10108/v1/proxies/{id} \
  -H "Authorization: Bearer $DONUT_API_KEY"
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/proxies/{id}", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
  },
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.get(
    "http://127.0.0.1:10108/v1/proxies/{id}",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$response = Invoke-RestMethod -Method GET -Uri "http://127.0.0.1:10108/v1/proxies/{id}" `
    -Headers $headers

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
{
  "id": "c5617755-0709-4820-832a-6b97a0a24f3c",
  "name": "Albania",
  "proxy_settings": {
    "proxy_type": "https",
    "host": "proxy.example.com",
    "port": 8080,
    "username": "user",
    "password": "secret"
  }
}
```

### PUT /v1/proxies/{id}

Send the full updated `proxy_settings` and optionally a new `name`.

**curl**

```bash
curl -sS -X PUT http://127.0.0.1:10108/v1/proxies/{id} \
  -H "Authorization: Bearer $DONUT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "name": "us-residential-rotating",
      "proxy_settings": {
        "proxy_type": "socks5",
        "host": "rotate.example.com",
        "port": 1080
      }
    }'
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/proxies/{id}", {
  method: "PUT",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "us-residential-rotating",
    "proxy_settings": {
      "proxy_type": "socks5",
      "host": "rotate.example.com",
      "port": 1080
    }
  }),
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.put(
    "http://127.0.0.1:10108/v1/proxies/{id}",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    json={
      "name": "us-residential-rotating",
      "proxy_settings": {
        "proxy_type": "socks5",
        "host": "rotate.example.com",
        "port": 1080
      }
    },
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$body = @'
{
  "name": "us-residential-rotating",
  "proxy_settings": {
    "proxy_type": "socks5",
    "host": "rotate.example.com",
    "port": 1080
  }
}
'@

$response = Invoke-RestMethod -Method PUT -Uri "http://127.0.0.1:10108/v1/proxies/{id}" `
    -Headers $headers -ContentType "application/json" -Body $body

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
{
  "id": "pxy_01J8...",
  "name": "us-residential-rotating",
  "proxy_settings": {
    "proxy_type": "socks5",
    "host": "rotate.example.com",
    "port": 1080,
    "username": null,
    "password": null
  }
}
```

### DELETE /v1/proxies/{id}

Profiles that referenced the proxy will have their `proxy_id` set to null.

**curl**

```bash
curl -sS -X DELETE http://127.0.0.1:10108/v1/proxies/{id} \
  -H "Authorization: Bearer $DONUT_API_KEY"
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/proxies/{id}", {
  method: "DELETE",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
  },
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.delete(
    "http://127.0.0.1:10108/v1/proxies/{id}",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$response = Invoke-RestMethod -Method DELETE -Uri "http://127.0.0.1:10108/v1/proxies/{id}" `
    -Headers $headers

$response | ConvertTo-Json -Depth 10
```

**Response**

```http
204 No Content
```

## VPNs

WireGuard VPN configs. Attach to a profile via `vpn_id`.

### GET /v1/vpns

Every VPN config stored locally.

**curl**

```bash
curl -sS -X GET http://127.0.0.1:10108/v1/vpns \
  -H "Authorization: Bearer $DONUT_API_KEY"
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/vpns", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
  },
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.get(
    "http://127.0.0.1:10108/v1/vpns",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$response = Invoke-RestMethod -Method GET -Uri "http://127.0.0.1:10108/v1/vpns" `
    -Headers $headers

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
[
  {
    "id": "22034ceb-7b76-456e-9cfe-a4b207751f8d",
    "name": "Test WG",
    "vpn_type": "WireGuard",
    "created_at": 1777203528,
    "last_used": null
  }
]
```

### POST /v1/vpns

`config_data` is the raw WireGuard `.conf` content. Newlines must be preserved.

**curl**

```bash
curl -sS -X POST http://127.0.0.1:10108/v1/vpns \
  -H "Authorization: Bearer $DONUT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "name": "DE — Frankfurt",
      "vpn_type": "WireGuard",
      "config_data": "[Interface]\nPrivateKey = <base64>\nAddress = 10.0.0.2/32\n\n[Peer]\nPublicKey = <base64>\nEndpoint = de.example.com:51820\nAllowedIPs = 0.0.0.0/0"
    }'
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/vpns", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "DE — Frankfurt",
    "vpn_type": "WireGuard",
    "config_data": "[Interface]\nPrivateKey = <base64>\nAddress = 10.0.0.2/32\n\n[Peer]\nPublicKey = <base64>\nEndpoint = de.example.com:51820\nAllowedIPs = 0.0.0.0/0"
  }),
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.post(
    "http://127.0.0.1:10108/v1/vpns",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    json={
      "name": "DE — Frankfurt",
      "vpn_type": "WireGuard",
      "config_data": "[Interface]\nPrivateKey = <base64>\nAddress = 10.0.0.2/32\n\n[Peer]\nPublicKey = <base64>\nEndpoint = de.example.com:51820\nAllowedIPs = 0.0.0.0/0"
    },
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$body = @'
{
  "name": "DE — Frankfurt",
  "vpn_type": "WireGuard",
  "config_data": "[Interface]\nPrivateKey = <base64>\nAddress = 10.0.0.2/32\n\n[Peer]\nPublicKey = <base64>\nEndpoint = de.example.com:51820\nAllowedIPs = 0.0.0.0/0"
}
'@

$response = Invoke-RestMethod -Method POST -Uri "http://127.0.0.1:10108/v1/vpns" `
    -Headers $headers -ContentType "application/json" -Body $body

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
{
  "id": "vpn_01J8...",
  "name": "DE — Frankfurt",
  "vpn_type": "WireGuard",
  "created_at": 1779226206,
  "last_used": null
}
```

### POST /v1/vpns/import

Same as `POST /v1/vpns`, but you pass the file `content` plus `filename` (used to derive `name` if omitted).

**curl**

```bash
curl -sS -X POST http://127.0.0.1:10108/v1/vpns/import \
  -H "Authorization: Bearer $DONUT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "filename": "de-frankfurt.conf",
      "name": "DE — Frankfurt",
      "content": "[Interface]\nPrivateKey = <base64>\n…\n[Peer]\nPublicKey = <base64>\nEndpoint = de.example.com:51820"
    }'
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/vpns/import", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "filename": "de-frankfurt.conf",
    "name": "DE — Frankfurt",
    "content": "[Interface]\nPrivateKey = <base64>\n…\n[Peer]\nPublicKey = <base64>\nEndpoint = de.example.com:51820"
  }),
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.post(
    "http://127.0.0.1:10108/v1/vpns/import",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    json={
      "filename": "de-frankfurt.conf",
      "name": "DE — Frankfurt",
      "content": "[Interface]\nPrivateKey = <base64>\n…\n[Peer]\nPublicKey = <base64>\nEndpoint = de.example.com:51820"
    },
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$body = @'
{
  "filename": "de-frankfurt.conf",
  "name": "DE — Frankfurt",
  "content": "[Interface]\nPrivateKey = <base64>\n…\n[Peer]\nPublicKey = <base64>\nEndpoint = de.example.com:51820"
}
'@

$response = Invoke-RestMethod -Method POST -Uri "http://127.0.0.1:10108/v1/vpns/import" `
    -Headers $headers -ContentType "application/json" -Body $body

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
{
  "id": "vpn_01J8...",
  "name": "DE — Frankfurt",
  "vpn_type": "WireGuard",
  "created_at": 1779226206,
  "last_used": null
}
```

### GET /v1/vpns/{id}

Returns metadata for a single VPN config. The raw key material is not exposed.

**curl**

```bash
curl -sS -X GET http://127.0.0.1:10108/v1/vpns/{id} \
  -H "Authorization: Bearer $DONUT_API_KEY"
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/vpns/{id}", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
  },
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.get(
    "http://127.0.0.1:10108/v1/vpns/{id}",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$response = Invoke-RestMethod -Method GET -Uri "http://127.0.0.1:10108/v1/vpns/{id}" `
    -Headers $headers

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
{
  "id": "22034ceb-7b76-456e-9cfe-a4b207751f8d",
  "name": "Test WG",
  "vpn_type": "WireGuard",
  "created_at": 1777203528,
  "last_used": null
}
```

### PUT /v1/vpns/{id}

Currently only the `name` field is updatable on existing VPNs.

**curl**

```bash
curl -sS -X PUT http://127.0.0.1:10108/v1/vpns/{id} \
  -H "Authorization: Bearer $DONUT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "name": "DE — Frankfurt (primary)"
    }'
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/vpns/{id}", {
  method: "PUT",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "name": "DE — Frankfurt (primary)"
  }),
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.put(
    "http://127.0.0.1:10108/v1/vpns/{id}",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    json={
      "name": "DE — Frankfurt (primary)"
    },
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$body = @'
{
  "name": "DE — Frankfurt (primary)"
}
'@

$response = Invoke-RestMethod -Method PUT -Uri "http://127.0.0.1:10108/v1/vpns/{id}" `
    -Headers $headers -ContentType "application/json" -Body $body

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
{
  "id": "vpn_01J8...",
  "name": "DE — Frankfurt (primary)",
  "vpn_type": "WireGuard",
  "created_at": 1779226206,
  "last_used": null
}
```

### DELETE /v1/vpns/{id}

Profiles that referenced the VPN will have their `vpn_id` set to null.

**curl**

```bash
curl -sS -X DELETE http://127.0.0.1:10108/v1/vpns/{id} \
  -H "Authorization: Bearer $DONUT_API_KEY"
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/vpns/{id}", {
  method: "DELETE",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
  },
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.delete(
    "http://127.0.0.1:10108/v1/vpns/{id}",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$response = Invoke-RestMethod -Method DELETE -Uri "http://127.0.0.1:10108/v1/vpns/{id}" `
    -Headers $headers

$response | ConvertTo-Json -Depth 10
```

**Response**

```http
204 No Content
```

## Browsers

Trigger browser-binary downloads and check installed versions.

### POST /v1/browsers/download

Triggers a download of the named browser at the named version (Chromium via Wayfern, Firefox via Camoufox).

**curl**

```bash
curl -sS -X POST http://127.0.0.1:10108/v1/browsers/download \
  -H "Authorization: Bearer $DONUT_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
      "browser": "wayfern",
      "version": "147.0.7727.138"
    }'
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/browsers/download", {
  method: "POST",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
    "Content-Type": "application/json",
  },
  body: JSON.stringify({
    "browser": "wayfern",
    "version": "147.0.7727.138"
  }),
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.post(
    "http://127.0.0.1:10108/v1/browsers/download",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    json={
      "browser": "wayfern",
      "version": "147.0.7727.138"
    },
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$body = @'
{
  "browser": "wayfern",
  "version": "147.0.7727.138"
}
'@

$response = Invoke-RestMethod -Method POST -Uri "http://127.0.0.1:10108/v1/browsers/download" `
    -Headers $headers -ContentType "application/json" -Body $body

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
{
  "started": true,
  "browser": "wayfern",
  "version": "147.0.7727.138"
}
```

### GET /v1/browsers/{browser}/versions

Versions are returned newest first.

**curl**

```bash
curl -sS -X GET http://127.0.0.1:10108/v1/browsers/{browser}/versions \
  -H "Authorization: Bearer $DONUT_API_KEY"
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/browsers/{browser}/versions", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
  },
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.get(
    "http://127.0.0.1:10108/v1/browsers/{browser}/versions",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$response = Invoke-RestMethod -Method GET -Uri "http://127.0.0.1:10108/v1/browsers/{browser}/versions" `
    -Headers $headers

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
[
  "147.0.7727.138",
  "147.0.7727.137"
]
```

### GET /v1/browsers/{browser}/versions/{version}/downloaded

Returns `true` when the browser+version pair is on disk.

**curl**

```bash
curl -sS -X GET http://127.0.0.1:10108/v1/browsers/{browser}/versions/{version}/downloaded \
  -H "Authorization: Bearer $DONUT_API_KEY"
```

**Node.js**

```javascript
// Node 18+ (built-in fetch). Set DONUT_API_KEY in your environment.
const response = await fetch("http://127.0.0.1:10108/v1/browsers/{browser}/versions/{version}/downloaded", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.DONUT_API_KEY}`,
  },
});

if (!response.ok) {
  throw new Error(`HTTP ${response.status}`);
}

const data = await response.json();
console.log(data);
```

**Python**

```python
# pip install requests
import os, requests

response = requests.get(
    "http://127.0.0.1:10108/v1/browsers/{browser}/versions/{version}/downloaded",
    headers={"Authorization": f"Bearer {os.environ['DONUT_API_KEY']}"},
    timeout=10,
)
response.raise_for_status()
print(response.json())
```

**PowerShell**

```powershell
$headers = @{
    Authorization = "Bearer $env:DONUT_API_KEY"
}

$response = Invoke-RestMethod -Method GET -Uri "http://127.0.0.1:10108/v1/browsers/{browser}/versions/{version}/downloaded" `
    -Headers $headers

$response | ConvertTo-Json -Depth 10
```

**Response**

```json
true
```
