# Service Accounts API

Service accounts are named identities that authenticate with API keys instead of passwords. They share the same role-based access control as human users. All endpoints require admin access.

## List service accounts

```
GET /api/bot-accounts
```

**Query parameters:**

| Parameter | Type | Description |
|-----------|------|-------------|
| `limit` | `integer` | Max results (default: 50) |
| `offset` | `integer` | Pagination offset (default: 0) |

**Response 200:**

```json
{
  "bots": [
    {
      "id": "a1b2c3d4-...",
      "external_id": "ci-bot",
      "display_name": "CI Bot",
      "account_type": "bot",
      "description": "Runs scheduled workflows",
      "status": "active",
      "roles": [
        { "role": "scheduler", "type": "member", "created_at": "2025-03-01T00:00:00.000Z" }
      ],
      "created_at": "2025-03-01T00:00:00.000Z",
      "updated_at": "2025-03-01T00:00:00.000Z"
    }
  ],
  "total": 1
}
```

## Get service account details

```
GET /api/bot-accounts/:id
```

**Response 200:** A single service account object.

**Response 404:**

```json
{ "error": "Bot not found" }
```

## Create service account

```
POST /api/bot-accounts
```

**Request body:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | `string` | yes | Unique identifier (used as `external_id`) |
| `display_name` | `string` | no | Human-readable name |
| `description` | `string` | no | Purpose of this service account |
| `roles` | `array` | no | Initial role assignments: `[{ role, type }]` |

**Response 201:** The created service account object.

**Response 409:**

```json
{ "error": "Bot with this name already exists" }
```

## Update service account

```
PUT /api/bot-accounts/:id
```

**Request body:**

| Field | Type | Description |
|-------|------|-------------|
| `display_name` | `string` | New display name |
| `description` | `string` | New description |
| `status` | `string` | `active`, `inactive`, or `suspended` |

**Response 200:** The updated service account object.

## Delete service account

```
DELETE /api/bot-accounts/:id
```

Deletes the service account and all its API keys (cascade).

**Response 200:**

```json
{ "deleted": true }
```

## Service account roles

Roles work identically to user roles.

```
GET    /api/bot-accounts/:id/roles
POST   /api/bot-accounts/:id/roles       { "role": "scheduler", "type": "member" }
DELETE /api/bot-accounts/:id/roles/:role
```

## API keys

### Generate key

```
POST /api/bot-accounts/:id/api-keys
```

**Request body:**

| Field | Type | Required | Description |
|-------|------|----------|-------------|
| `name` | `string` | yes | Key name (unique per service account) |
| `scopes` | `string[]` | no | Allowed scopes (default: `[]`) |
| `expires_at` | `string` | no | ISO 8601 expiry date |

**Response 201:**

```json
{
  "id": "key-uuid",
  "rawKey": "lt_bot_a1b2c3d4e5f6..."
}
```

The `rawKey` is shown **once**. It cannot be retrieved again.

### API Key Scopes

Scopes control what an API key can access when used with the `/mcp` endpoint:

| Scope | Description |
|-------|-------------|
| `mcp:read` | Read-safe tools only (57 tools) — discovery, monitoring, queries |
| `mcp:full` | All tools (110 tools) — can modify state, invoke workflows, manage resources |

A key with `mcp:read` only sees tools marked `read_safe: true`. A key with both `mcp:read` and `mcp:full` sees all tools. Keys without MCP scopes have no MCP tool filtering applied.

**Recommended keys per service account:**
- **Read key**: scopes `["mcp:read"]` — safe to hand to monitoring systems
- **Full key**: scopes `["mcp:read", "mcp:full"]` — for automation and orchestration

### List keys

```
GET /api/bot-accounts/:id/api-keys
```

Returns key metadata without secret values.

```json
{
  "keys": [
    {
      "id": "key-uuid",
      "name": "production",
      "scopes": ["mcp:tool:call"],
      "last_used_at": "2025-03-15T12:00:00.000Z",
      "created_at": "2025-03-01T00:00:00.000Z"
    }
  ]
}
```

### Revoke key

```
DELETE /api/bot-accounts/:id/api-keys/:keyId
```

**Response 200:**

```json
{ "revoked": true }
```

## Using a service account API key

Include the raw key as a Bearer token in any API request:

```bash
curl -H "Authorization: Bearer lt_bot_a1b2c3d4e5f6..." \
  http://localhost:3000/api/tasks
```

The service account authenticates through the same middleware as human users. RBAC checks use the account's assigned roles.
