---
name: clinic-api
description: |
  Query PingCAP Clinic cluster information via REST API.
  Requires Internal API Key authentication. Use when looking up TiDB Cloud cluster details,
  searching clusters by ID, tenant ID, or tenant name.
---

# Clinic API

Query TiDB Cloud cluster metadata from PingCAP Clinic.

## Key Concepts

### Search Query Types

The `query` parameter in List API accepts multiple search types:

| Query Type | Example | Description |
|------------|---------|-------------|
| Tenant Name | `"Acme Corp"` | Search by organization/tenant display name |
| Tenant ID | `"1372813089209271775"` | Search by numeric tenant ID |
| Cluster ID | `"10040083716234509777"` | Search by numeric cluster ID |
| Cluster Name | `"prod-cluster"` | Search by cluster display name |

**When user asks about a tenant by name**, use that name directly in `clinic_search_clusters`:

```bash
# Search by tenant name
clinic_search_clusters "PingCAP"

# Search by tenant ID  
clinic_search_clusters "1372813089209271775"

# Search by cluster ID
clinic_search_clusters "10040083716234509777"
```

### ID Types (IMPORTANT)

| ID | User-Facing | Description |
|----|-------------|-------------|
| `tenantID` | YES | User's tenant ID, what users see and reference |
| `orgID` | NO | Clinic internal ID, only used in API paths |
| `clusterID` | YES | Cluster ID, same in both user and API context |
| `parentID` | NO | For Premium clusters, points to Resource Pool cluster |

**Critical**: When user says "tenant ID", they mean `tenantID`. The `orgID` in API responses is internal and must be extracted from List API to use in Get API.

### Cluster Types and Topology

| Type | Deploy Type | Has Topology | How to Get Topology |
|------|-------------|--------------|---------------------|
| Dedicated | `dedicated` | YES | `components` field in Get Cluster response |
| Resource Pool | `resource_pool` | YES | `/clusters/{clusterID}/resource-pool/components` API |
| Premium | `premium` | NO | Get `parentID` → query Resource Pool's components |
| Starter/Serverless | `starter` | NO | No topology (shared infrastructure) |

**Only Dedicated and Resource Pool clusters have component topology** (TiKV, TiDB, PD, TiFlash specs, node counts, storage).

## Architecture

```
┌─────────────────────────────────────────────────────────────────────────────┐
│                      Auth Flow (API Key)                                     │
├─────────────────────────────────────────────────────────────────────────────┤
│  1. Check CLINIC_API_KEY in environment or .env file                         │
│  2. Use API Key with Bearer Token authentication                             │
└─────────────────────────────────────────────────────────────────────────────┘
```

### Prerequisites

1. You must be an **internal user** (`internal=true`)
2. Login to [clinic.pingcap.com](https://clinic.pingcap.com)
3. Go to **User Profile** and create an Access Key
4. Save the key to `.env` file:

```bash
# .env
CLINIC_API_KEY="your-api-key-here"
```

> **Important**: The `key` is only shown once at creation time. Save it securely!

**IMPORTANT FOR AI AGENTS**:
- DO NOT ask user to choose between options
- Just run `get_clinic_auth` - it reads API Key from environment

## Quick Start

```bash
source ~/.claude/skills/clinic-api/clinic-token.sh
get_clinic_auth
clinic_get_cluster_by_id "CLUSTER_ID"
```

The script will automatically:
1. Read CLINIC_API_KEY from environment or .env file
2. Use Bearer Token authentication for all API calls

## Authentication

API calls use Bearer Token authentication with Internal API Key:

```bash
curl -H "Authorization: Bearer <your-api-key>" \
  https://clinic.pingcap.com/clinic/api/v1/orgs
```

Alternative: Basic Auth (also supported):

```bash
curl -u "api_key:<your-api-key>" \
  https://clinic.pingcap.com/clinic/api/v1/orgs
```

Internal API Key users can access **all** Clinic API endpoints without URI restrictions.

## Typical Workflows

### Get Cluster Info by Cluster ID

```bash
source skills/clinic-api/clinic-token.sh
get_clinic_auth

# One-liner (auto-discovers orgID)
clinic_get_cluster_by_id "10040083716234509777"
```

### List All Clusters for a Tenant

```bash
# Query by tenant name (organization name)
clinic_search_clusters "PingCAP"

# Query by tenant ID (user-facing ID)
clinic_search_clusters "1372813089209271775"

# Query by cluster name
clinic_search_clusters "prod-cluster"
```

### Get Premium Cluster Topology

Premium clusters get topology from their parent Resource Pool:

```bash
# Step 1: Get cluster details to find parentID
CLUSTER=$(clinic_get_cluster_by_id "10040083716234509777")
PARENT_ID=$(echo "$CLUSTER" | jq -r '.parentID // empty')
ORG_ID=$(clinic_search_clusters "10040083716234509777" | jq -r '.items[0].orgID')

# Step 2: Get Resource Pool's component topology
if [ -n "$PARENT_ID" ]; then
  curl -s "https://clinic.pingcap.com/clinic/api/v1/orgs/${ORG_ID}/clusters/${PARENT_ID}/resource-pool/components" \
    -H "Authorization: Bearer ${CLINIC_API_KEY}"
fi
```

### Get Dedicated Cluster Topology

Dedicated clusters have topology in the `components` field of Get Cluster response:

```bash
# Components are included in the cluster response
clinic_get_cluster_by_id "10622168475167794563" | jq '.components'
```

### Direct API Calls

```bash
source skills/clinic-api/clinic-token.sh
get_clinic_auth

# Search clusters
curl -s "https://clinic.pingcap.com/clinic/api/v1/dashboard/clusters" \
  -H "Authorization: Bearer ${CLINIC_API_KEY}" \
  -G \
  --data-urlencode "query=10472453129614424594" \
  --data-urlencode "show_deleted=false" \
  --data-urlencode "limit=10"

# Get cluster details (orgID from search response, NOT tenant ID)
curl -s "https://clinic.pingcap.com/clinic/api/v1/orgs/${ORG_ID}/clusters/${CLUSTER_ID}" \
  -H "Authorization: Bearer ${CLINIC_API_KEY}"
```

## API Endpoints

### 1. List/Search Clusters

```
GET /clinic/api/v1/dashboard/clusters
```

Search clusters by tenant name, tenant ID, cluster ID, or cluster name.

| Parameter | Required | Description |
|-----------|----------|-------------|
| `query` | No | Tenant name, tenant ID, cluster ID, or cluster name |
| `show_deleted` | No | Include deleted clusters (default: false) |
| `deploy_type_v2` | No | Filter by type: `premium`, `dedicated` |
| `sort` | No | Sort field |
| `order` | No | Sort order |
| `limit` | No | Results per page (default: 10) |
| `page` | No | Page number (default: 1) |

**Response** (key fields):
```json
{
  "total": 1,
  "items": [{
    "tenantID": "1372813089209271775",    // User-facing tenant ID
    "orgID": "1372813089197007686",       // Internal, use in Get API path
    "clusterID": "10040083716234509777",
    "clusterName": "my-cluster",
    "clusterStatus": "active",
    "clusterDeployType": "premium",       // or "dedicated"
    "clusterVersion": "v8.5.4",
    "clusterRegionName": "ap-southeast-1",
    "clusterProviderName": "alicloud",
    "createTime": "2024-01-15T10:30:00Z",
    "deleteTime": null
  }]
}
```

### 2. Get Cluster Details

```
GET /clinic/api/v1/orgs/{orgID}/clusters/{clusterID}
```

**Note**: `{orgID}` is from List API response, NOT user's tenant ID.

**Response for Dedicated** (has `components` field):
```json
{
  "id": "10622168475167794563",
  "name": "my-dedicated",
  "version": "v8.5.4",
  "status": "active",
  "region": "ap-southeast-1",
  "provider": "aws",
  "deployType": "dedicated",
  "components": {
    "tidb": { "nodeQuantity": 2, "nodeSize": "4C16G", ... },
    "tikv": { "nodeQuantity": 3, "nodeSize": "8C32G", "storageGB": 500, ... },
    "pd": { "nodeQuantity": 3, "nodeSize": "2C8G", ... }
  }
}
```

**Response for Premium** (no components, has `parentID`):
```json
{
  "id": "10040083716234509777",
  "name": "my-premium",
  "version": "v8.5.4",
  "status": "active",
  "deployType": "premium",
  "parentID": "2015406318478692352",
  "minRCU": 5000,
  "maxRCU": 5000
}
```

### 3. Get Resource Pool Components (for topology)

```
GET /clinic/api/v1/orgs/{orgID}/clusters/{resourcePoolClusterID}/resource-pool/components
```

Use this for Resource Pool clusters (or Premium clusters via `parentID`) to get component topology.

**Response**:
```json
{
  "tikv": { "nodeQuantity": 3, "nodeSize": "8C64G", "storageGB": 1000, ... },
  "tidb": { "nodeQuantity": 2, "nodeSize": "4C16G", ... },
  "pd": { "nodeQuantity": 3, "nodeSize": "2C8G", ... },
  "tiflash": { "nodeQuantity": 0, ... }
}
```

### 4. Get Cluster Topology (Summary)

| Cluster Type | API to Get Topology |
|--------------|---------------------|
| Dedicated | `GET /orgs/{orgID}/clusters/{clusterID}` → `components` field |
| Resource Pool | `GET /orgs/{orgID}/clusters/{clusterID}/resource-pool/components` |
| Premium | Get `parentID` from cluster → use Resource Pool API above |
| Starter | No topology available |

## Environment Variables

| Variable | Description |
|----------|-------------|
| `CLINIC_API_KEY` | Internal API Key (required) |
| `ENV_FILE` | Path to .env file (default: `.env`) |

## Troubleshooting

| Issue | Cause | Solution |
|-------|-------|----------|
| 401 Unauthorized | Invalid or expired API Key | Create new API Key at clinic.pingcap.com User Profile |
| 403 Forbidden | Not an internal user | Contact admin to enable `internal=true` for your account |
| CLINIC_API_KEY not set | Missing configuration | Add `CLINIC_API_KEY="..."` to .env file |

## Agent Integration

**DO NOT ask user questions. Just run:**

```bash
source ~/.claude/skills/clinic-api/clinic-token.sh
get_clinic_auth  # Fully automatic - handles everything
clinic_get_cluster_by_id "10040083716234509777"
```
