# FTP Accounts

<a id="get-api-v1-accounts-username-ftp"></a>
#### `GET /api/v1/accounts/{username}/ftp`

*List FTP accounts for a hosting account*

Returns every Pure-FTPd user owned by the given account.

**Path parameters:**

| Name | Type | Required | Notes |
|------|------|----------|-------|
| `username` | string | yes | — |

**Responses:**

| Status | Schema | Description |
|--------|--------|-------------|
| `200` | `ApiSuccess_list_FTPAccountResponse__` | Successful Response |
| `422` | `HTTPValidationError` | Validation Error |

**Response example (200):**

```json
{
  "data": [
    {
      "account": "...",
      "created_at": "...",
      "directory": "...",
      "is_orphan": "...",
      "quota_mb": "...",
      "status": "...",
      "username": "..."
    }
  ],
  "message": "",
  "status": "success",
  "warnings": [
    "string"
  ]
}
```

**cURL example:**

```bash
curl -X GET \
  -H "X-WHost-Key: $WHOST_API_KEY" \
  -H "X-WHost-Timestamp: $(date +%s)" \
  -H "X-WHost-Nonce: $(openssl rand -hex 16)" \
  -H "X-WHost-Signature: $(compute_hmac)" \
  https://your-server:2000/api/v1/accounts/{username}/ftp
```

---

<a id="post-api-v1-accounts-username-ftp"></a>
#### `POST /api/v1/accounts/{username}/ftp`

*Create FTP account*

Create a chrooted Pure-FTPd user under the hosting account's home directory. Enforces the plan's `max_ftp_accounts` cap.

**Path parameters:**

| Name | Type | Required | Notes |
|------|------|----------|-------|
| `username` | string | yes | — |

**Body fields:**

| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `directory` | string | no | default `/`; minLength=1; maxLength=255; pattern=`^/[a-zA-Z0-9/_.\-]*$` |
| `password` | string | yes | minLength=8; maxLength=128 |
| `quota_mb` | integer | no | default `0`; minimum=0.0; maximum=999999.0 |
| `username` | string | yes | minLength=1; maxLength=32 |

**Request body example:**

```json
{
  "directory": "/",
  "password": "REPLACE_ME",
  "quota_mb": 0,
  "username": "alice"
}
```

**Responses:**

| Status | Schema | Description |
|--------|--------|-------------|
| `200` | `ApiSuccess_FTPAccountResponse_` | Successful Response |
| `422` | `HTTPValidationError` | Validation Error |

**Response example (200):**

```json
{
  "data": {
    "account": "...",
    "created_at": "...",
    "directory": "string",
    "is_orphan": false,
    "quota_mb": 0,
    "status": "active",
    "username": "alice"
  },
  "message": "",
  "status": "success",
  "warnings": [
    "string"
  ]
}
```

**cURL example:**

```bash
curl -X POST \
  -H "X-WHost-Key: $WHOST_API_KEY" \
  -H "X-WHost-Timestamp: $(date +%s)" \
  -H "X-WHost-Nonce: $(openssl rand -hex 16)" \
  -H "X-WHost-Signature: $(compute_hmac)" \
  -H "Content-Type: application/json" \
  -d @body.json \
  https://your-server:2000/api/v1/accounts/{username}/ftp
```

---

<a id="delete-api-v1-accounts-username-ftp-ftp-user"></a>
#### `DELETE /api/v1/accounts/{username}/ftp/{ftp_user}`

*Delete FTP account*

Remove the Pure-FTPd user and its DB record.

**Path parameters:**

| Name | Type | Required | Notes |
|------|------|----------|-------|
| `username` | string | yes | — |
| `ftp_user` | string | yes | — |

**Responses:**

| Status | Schema | Description |
|--------|--------|-------------|
| `200` | `MessageResponse` | Successful Response |
| `422` | `HTTPValidationError` | Validation Error |

**Response example (200):**

```json
{
  "message": "string",
  "status": "success"
}
```

**cURL example:**

```bash
curl -X DELETE \
  -H "X-WHost-Key: $WHOST_API_KEY" \
  -H "X-WHost-Timestamp: $(date +%s)" \
  -H "X-WHost-Nonce: $(openssl rand -hex 16)" \
  -H "X-WHost-Signature: $(compute_hmac)" \
  https://your-server:2000/api/v1/accounts/{username}/ftp/{ftp_user}
```

---

<a id="put-api-v1-accounts-username-ftp-ftp-user"></a>
#### `PUT /api/v1/accounts/{username}/ftp/{ftp_user}`

*Update FTP account*

Change password, target directory or quota for an existing FTP user. Fields equal to the stored values are not a change; a request that changes nothing writes no audit entry.

**Path parameters:**

| Name | Type | Required | Notes |
|------|------|----------|-------|
| `username` | string | yes | — |
| `ftp_user` | string | yes | — |

**Body fields:**

| Field | Type | Required | Notes |
|-------|------|----------|-------|
| `directory` | string | no | — |
| `password` | string | no | — |
| `quota_mb` | integer | no | — |

**Request body example:**

```json
{
  "directory": "string",
  "password": "string",
  "quota_mb": 0
}
```

**Responses:**

| Status | Schema | Description |
|--------|--------|-------------|
| `200` | `ApiSuccess_FTPAccountResponse_` | Successful Response |
| `422` | `HTTPValidationError` | Validation Error |

**Response example (200):**

```json
{
  "data": {
    "account": "...",
    "created_at": "...",
    "directory": "string",
    "is_orphan": false,
    "quota_mb": 0,
    "status": "active",
    "username": "alice"
  },
  "message": "",
  "status": "success",
  "warnings": [
    "string"
  ]
}
```

**cURL example:**

```bash
curl -X PUT \
  -H "X-WHost-Key: $WHOST_API_KEY" \
  -H "X-WHost-Timestamp: $(date +%s)" \
  -H "X-WHost-Nonce: $(openssl rand -hex 16)" \
  -H "X-WHost-Signature: $(compute_hmac)" \
  -H "Content-Type: application/json" \
  -d @body.json \
  https://your-server:2000/api/v1/accounts/{username}/ftp/{ftp_user}
```

---

<a id="get-api-v1-ftp"></a>
#### `GET /api/v1/ftp`

*List every FTP account on the server (admin)*

Server-wide listing including rows whose owning hosting account no longer exists (`is_orphan=true`). Used by the orphan-cleanup operator tool.

**Responses:**

| Status | Schema | Description |
|--------|--------|-------------|
| `200` | `ApiSuccess_list_FTPAccountResponse__` | Successful Response |

**Response example (200):**

```json
{
  "data": [
    {
      "account": "...",
      "created_at": "...",
      "directory": "...",
      "is_orphan": "...",
      "quota_mb": "...",
      "status": "...",
      "username": "..."
    }
  ],
  "message": "",
  "status": "success",
  "warnings": [
    "string"
  ]
}
```

**cURL example:**

```bash
curl -X GET \
  -H "X-WHost-Key: $WHOST_API_KEY" \
  -H "X-WHost-Timestamp: $(date +%s)" \
  -H "X-WHost-Nonce: $(openssl rand -hex 16)" \
  -H "X-WHost-Signature: $(compute_hmac)" \
  https://your-server:2000/api/v1/ftp
```

---

<a id="delete-api-v1-ftp-orphans"></a>
#### `DELETE /api/v1/ftp/orphans`

*Bulk-cleanup orphan FTP rows*

Removes every FTP row whose hosting account file is missing. Returns the list of deleted ftp usernames + count.

**Responses:**

| Status | Schema | Description |
|--------|--------|-------------|
| `200` | `ApiSuccess_FTPOrphanCleanupData_` | Successful Response |

**Response example (200):**

```json
{
  "data": {
    "count": 0,
    "deleted": []
  },
  "message": "",
  "status": "success",
  "warnings": [
    "string"
  ]
}
```

**cURL example:**

```bash
curl -X DELETE \
  -H "X-WHost-Key: $WHOST_API_KEY" \
  -H "X-WHost-Timestamp: $(date +%s)" \
  -H "X-WHost-Nonce: $(openssl rand -hex 16)" \
  -H "X-WHost-Signature: $(compute_hmac)" \
  https://your-server:2000/api/v1/ftp/orphans
```

---

<a id="delete-api-v1-ftp-orphans-ftp-user"></a>
#### `DELETE /api/v1/ftp/orphans/{ftp_user}`

*Delete a single orphan FTP row*

Targeted cleanup of one orphan FTP entry by username.

**Path parameters:**

| Name | Type | Required | Notes |
|------|------|----------|-------|
| `ftp_user` | string | yes | — |

**Responses:**

| Status | Schema | Description |
|--------|--------|-------------|
| `200` | `MessageResponse` | Successful Response |
| `422` | `HTTPValidationError` | Validation Error |

**Response example (200):**

```json
{
  "message": "string",
  "status": "success"
}
```

**cURL example:**

```bash
curl -X DELETE \
  -H "X-WHost-Key: $WHOST_API_KEY" \
  -H "X-WHost-Timestamp: $(date +%s)" \
  -H "X-WHost-Nonce: $(openssl rand -hex 16)" \
  -H "X-WHost-Signature: $(compute_hmac)" \
  https://your-server:2000/api/v1/ftp/orphans/{ftp_user}
```

---
