# Operator API

> For the people who run the service: suspend an organization or lift a suspension, and review the abuse guard's flags. These routes need the operator token.

- [Suspend an organization (operators)](#suspend-an-organization-operators): `POST /v1/operator/organizations/{organization_id}/suspend`
- [Lift a suspension (operators)](#lift-a-suspension-operators): `POST /v1/operator/organizations/{organization_id}/resume`
- [List abuse flags (operators)](#list-abuse-flags-operators): `GET /v1/operator/abuse-flags`
- [Resolve an abuse flag (operators)](#resolve-an-abuse-flag-operators): `POST /v1/operator/abuse-flags/{flag_id}/resolve`

## Suspend an organization (operators)

`POST /v1/operator/organizations/{organization_id}/suspend`

Suspend an organization (the kill switch): its machines are stopped, new
creates, starts, and restarts are refused, nothing may run commands or
open terminals or desktops in it (`403 organization_suspended`), and its
open terminal and desktop tickets and channels are revoked. Its data is
kept. Suspending a suspended organization changes nothing.

- **Authentication:** none on this route.
- **Who:** Service operators (operator token).

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `organization_id` | path | `string (uuid)` | Yes |  |
| `X-VMYard-Operator-Token` | header | `string` | Yes | Operator token from the service configuration |

**Request body** (`application/json`, [`OperatorActionRequest`](/docs/api/schemas#operatoractionrequest))

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `operator` | `string` | Yes | The individual operator acting (a name or work email), recorded in the audit log; 1-200 characters. |
| `reason` | `string` | Yes | Why; recorded in the audit log, 1-500 characters. A suspension's reason is shown to operators only. |

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| `200` | — | [`SuspensionDto`](/docs/api/schemas#suspensiondto) |
| `401` | Not signed in, or the API key is malformed, expired, or revoked (`unauthenticated`, `invalid_api_key`). | [`ProblemDetails`](/docs/api/schemas#problemdetails) |
| `404` | operator access is not configured or the organization is unknown | [`ProblemDetails`](/docs/api/schemas#problemdetails) |
| `422` | Invalid request (`invalid_request`); `field_errors` names the fields. | [`ProblemDetails`](/docs/api/schemas#problemdetails) |

```sh title="Request"
curl -X POST "$VMYARD_API_URL/v1/operator/organizations/$ORGANIZATION_ID/suspend" \
  -H "X-VMYard-Operator-Token: $X_VMYARD_OPERATOR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "operator": "string",
  "reason": "string"
}'
```

```json title="Response 200"
{
  "already_suspended": false,
  "channels_revoked": 0,
  "machines_stopping": 0,
  "organization_id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
  "reason": "string",
  "suspended_at": "string",
  "tickets_revoked": 0
}
```

## Lift a suspension (operators)

`POST /v1/operator/organizations/{organization_id}/resume`

Lift a suspension. Machines it stopped stay stopped until members start
them.

- **Authentication:** none on this route.
- **Who:** Service operators (operator token).

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `organization_id` | path | `string (uuid)` | Yes |  |
| `X-VMYard-Operator-Token` | header | `string` | Yes | Operator token from the service configuration |

**Request body** (`application/json`, [`OperatorActionRequest`](/docs/api/schemas#operatoractionrequest))

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `operator` | `string` | Yes | The individual operator acting (a name or work email), recorded in the audit log; 1-200 characters. |
| `reason` | `string` | Yes | Why; recorded in the audit log, 1-500 characters. A suspension's reason is shown to operators only. |

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| `200` | — | [`ResumeDto`](/docs/api/schemas#resumedto) |
| `401` | Not signed in, or the API key is malformed, expired, or revoked (`unauthenticated`, `invalid_api_key`). | [`ProblemDetails`](/docs/api/schemas#problemdetails) |
| `404` | operator access is not configured or the organization is unknown | [`ProblemDetails`](/docs/api/schemas#problemdetails) |
| `422` | Invalid request (`invalid_request`); `field_errors` names the fields. | [`ProblemDetails`](/docs/api/schemas#problemdetails) |

```sh title="Request"
curl -X POST "$VMYARD_API_URL/v1/operator/organizations/$ORGANIZATION_ID/resume" \
  -H "X-VMYard-Operator-Token: $X_VMYARD_OPERATOR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "operator": "string",
  "reason": "string"
}'
```

```json title="Response 200"
{
  "organization_id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
  "resumed": false
}
```

## List abuse flags (operators)

`GET /v1/operator/abuse-flags`

The sustained-CPU guard's flags, newest first, for review.

- **Authentication:** none on this route.
- **Who:** Service operators (operator token).

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `status` | query | [`AbuseFlagStatusDto`](/docs/api/schemas#abuseflagstatusdto) | No | `open` (default) or `all`. |
| `limit` | query | `integer` | No | 1-500, default 100; newest first. |
| `X-VMYard-Operator-Token` | header | `string` | Yes | Operator token from the service configuration |

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| `200` | — | [`AbuseFlagPage`](/docs/api/schemas#abuseflagpage) |
| `401` | Not signed in, or the API key is malformed, expired, or revoked (`unauthenticated`, `invalid_api_key`). | [`ProblemDetails`](/docs/api/schemas#problemdetails) |
| `404` | operator access is not configured | [`ProblemDetails`](/docs/api/schemas#problemdetails) |

```sh title="Request"
curl "$VMYARD_API_URL/v1/operator/abuse-flags" \
  -H "X-VMYard-Operator-Token: $X_VMYARD_OPERATOR_TOKEN"
```

```json title="Response 200"
{
  "items": [
    {
      "action": "string",
      "created_at": "string",
      "id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
      "kind": "string",
      "machine_id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
      "min_cpu_permille": 0,
      "organization_id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
      "resolution": "string",
      "resolution_note": "string",
      "resolved_at": "string",
      "stop_operation_id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
      "window_seconds": 0,
      "window_start": "string"
    }
  ]
}
```

## Resolve an abuse flag (operators)

`POST /v1/operator/abuse-flags/{flag_id}/resolve`

Resolve a flag after review. A resolved flag stays resolved; a second
resolution changes nothing and returns it as it is.

- **Authentication:** none on this route.
- **Who:** Service operators (operator token).

**Parameters**

| Name | In | Type | Required | Description |
| --- | --- | --- | --- | --- |
| `flag_id` | path | `string (uuid)` | Yes |  |
| `X-VMYard-Operator-Token` | header | `string` | Yes | Operator token from the service configuration |

**Request body** (`application/json`, [`ResolveAbuseFlagRequest`](/docs/api/schemas#resolveabuseflagrequest))

| Field | Type | Required | Description |
| --- | --- | --- | --- |
| `note` | `string` | Yes | What the review found, 1-500 characters. |
| `operator` | `string` | Yes | The individual operator acting, 1-200 characters. |
| `resolution` | [`FlagResolutionDto`](/docs/api/schemas#flagresolutiondto) | Yes |  |

**Responses**

| Status | Description | Body |
| --- | --- | --- |
| `200` | — | [`AbuseFlagDto`](/docs/api/schemas#abuseflagdto) |
| `401` | Not signed in, or the API key is malformed, expired, or revoked (`unauthenticated`, `invalid_api_key`). | [`ProblemDetails`](/docs/api/schemas#problemdetails) |
| `404` | operator access is not configured or the flag is unknown | [`ProblemDetails`](/docs/api/schemas#problemdetails) |
| `422` | Invalid request (`invalid_request`); `field_errors` names the fields. | [`ProblemDetails`](/docs/api/schemas#problemdetails) |

```sh title="Request"
curl -X POST "$VMYARD_API_URL/v1/operator/abuse-flags/$FLAG_ID/resolve" \
  -H "X-VMYard-Operator-Token: $X_VMYARD_OPERATOR_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{
  "note": "string",
  "operator": "string",
  "resolution": "dismissed"
}'
```

```json title="Response 200"
{
  "action": "string",
  "created_at": "string",
  "id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
  "kind": "string",
  "machine_id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
  "min_cpu_permille": 0,
  "organization_id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
  "resolution": "string",
  "resolution_note": "string",
  "resolved_at": "string",
  "stop_operation_id": "6f1c2d3e-4b5a-4c7d-8e9f-0a1b2c3d4e5f",
  "window_seconds": 0,
  "window_start": "string"
}
```
