> ## Documentation Index
> Fetch the complete documentation index at: https://docs.plugged.in/llms.txt
> Use this file to discover all available pages before exploring further.

# API Reference

> Complete API documentation for the Plugged.in platform

# API Reference

<Info>
  The Plugged.in API provides programmatic access to manage MCP servers, documents, and platform features. All API endpoints are available in both the cloud platform and self-hosted installations.
</Info>

## Base URLs

<Tabs>
  <Tab title="Cloud Platform">
    ```
    https://plugged.in/api
    ```
  </Tab>

  <Tab title="Self-Hosted">
    ```
    https://your-domain.com/api
    ```
  </Tab>

  <Tab title="Local Development">
    ```
    http://localhost:12005/api
    ```
  </Tab>
</Tabs>

## Authentication

<Warning>
  **Important:** All API endpoints require authentication unless explicitly marked as public. Always include your API key in the Authorization header for every request.
</Warning>

See the [Authentication Guide](/api/authentication) for detailed information on obtaining and managing API keys.

### Quick Start

Include your API key in the request headers for all API calls:

```bash theme={null}
Authorization: Bearer YOUR_API_KEY
```

### Public Endpoints

Only the following endpoints are accessible without authentication:

* `GET /api/search` - Public search (with rate limiting)
* `GET /api/servers/{uuid}` - Public server information (if server is public)
* `GET /api/users/{username}` - Public user profiles

## Rate Limiting

API endpoints have different rate limits based on the operation type:

| Endpoint Type        | Limit        | Window     |
| -------------------- | ------------ | ---------- |
| Authentication       | 5 requests   | 15 minutes |
| General API          | 60 requests  | 1 minute   |
| Public Search        | 100 requests | 1 minute   |
| Sensitive Operations | 10 requests  | 1 hour     |
| AI Documents         | 10 requests  | 1 hour     |

## API Endpoints

### Search & Discovery

#### Search MCP Servers

<Info>
  This endpoint is public but has stricter rate limiting for unauthenticated requests. Authenticated requests get higher rate limits.
</Info>

Search for MCP servers in the registry and community.

<CodeGroup>
  ```bash cURL (Authenticated) theme={null}
  curl "https://plugged.in/api/search?q=database&source=registry" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```bash cURL (Public) theme={null}
  curl "https://plugged.in/api/search?q=database&source=registry"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://plugged.in/api/search?q=database&source=registry', {
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY'
    }
  });
  const data = await response.json();
  ```

  ```python Python theme={null}
  import requests

  response = requests.get(
    'https://plugged.in/api/search',
    params={'q': 'database', 'source': 'registry'},
    headers={'Authorization': 'Bearer YOUR_API_KEY'}
  )
  data = response.json()
  ```
</CodeGroup>

**Query Parameters:**

* `q` (string, required) - Search query
* `source` (string) - Filter by source: `registry`, `community`, `all`
* `package` (string) - Filter by package type: `npm`, `docker`, `pypi`
* `repository` (string) - Filter by repository source
* `sort` (string) - Sort results: `relevance`, `recent`, `popular`
* `limit` (integer) - Results per page (default: 20, max: 100)
* `offset` (integer) - Pagination offset

**Response:**

```json theme={null}
{
  "servers": [
    {
      "uuid": "123e4567-e89b-12d3-a456-426614174000",
      "slug": "example-server",
      "title": "Example MCP Server",
      "description": "A sample MCP server",
      "repository_url": "https://github.com/user/repo",
      "package_type": "npm",
      "installation_count": 1250,
      "rating": 4.5,
      "transports": ["stdio", "sse"]
    }
  ],
  "total": 42,
  "limit": 20,
  "offset": 0
}
```

### MCP Servers

#### Get Server Details

Retrieve detailed information about a specific MCP server.

```bash theme={null}
GET /api/servers/{uuid}
```

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://plugged.in/api/servers/123e4567-e89b-12d3-a456-426614174000" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://plugged.in/api/servers/123e4567-e89b-12d3-a456-426614174000', {
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY'
    }
  });
  const server = await response.json();
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "uuid": "123e4567-e89b-12d3-a456-426614174000",
  "name": "Example Server",
  "transport": "stdio",
  "command": "node",
  "args": ["index.js"],
  "env": {
    "API_KEY": "***"
  },
  "tools": [
    {
      "name": "example_tool",
      "description": "An example tool",
      "parameters": {}
    }
  ],
  "resources": [],
  "prompts": []
}
```

#### Create MCP Server

Add a new MCP server to your profile.

```bash theme={null}
POST /api/mcp-servers
```

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://plugged.in/api/mcp-servers" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "name": "My Server",
      "transport": "stdio",
      "command": "node",
      "args": ["server.js"],
      "env": {
        "API_KEY": "my-api-key"
      }
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://plugged.in/api/mcp-servers', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      name: 'My Server',
      transport: 'stdio',
      command: 'node',
      args: ['server.js'],
      env: {
        API_KEY: 'my-api-key'
      }
    })
  });
  ```
</CodeGroup>

**Request Body:**

```json theme={null}
{
  "name": "string (required)",
  "transport": "stdio | sse | http",
  "command": "string (for stdio)",
  "args": ["array", "of", "arguments"],
  "url": "string (for http/sse)",
  "env": {
    "KEY": "value"
  },
  "notes": "optional notes"
}
```

### Documents API

#### List Documents

Get documents from your library.

```bash theme={null}
GET /api/documents
```

**Query Parameters:**

* `profileUuid` (string, required) - Profile UUID
* `limit` (integer) - Results per page (default: 20)
* `offset` (integer) - Pagination offset
* `search` (string) - Search query
* `source` (string) - Filter by source: `upload`, `ai_generated`, `api`

#### Upload Document

Upload a document to your library.

```bash theme={null}
POST /api/documents/upload
```

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://plugged.in/api/documents/upload" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -F "file=@document.pdf" \
    -F "profileUuid=your-profile-uuid"
  ```

  ```javascript JavaScript theme={null}
  const formData = new FormData();
  formData.append('file', fileInput.files[0]);
  formData.append('profileUuid', 'your-profile-uuid');

  const response = await fetch('https://plugged.in/api/documents/upload', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY'
    },
    body: formData
  });
  ```
</CodeGroup>

#### Search Documents

Semantic search across your document library.

```bash theme={null}
POST /api/documents/search
```

**Request Body:**

```json theme={null}
{
  "query": "search query",
  "profileUuid": "profile-uuid",
  "filters": {
    "source": "ai_generated",
    "modelName": "claude-3",
    "dateFrom": "2024-01-01",
    "dateTo": "2024-12-31"
  },
  "limit": 10
}
```

### Collections API

#### Get Collections

Retrieve collections for a profile.

```bash theme={null}
GET /api/collections/{profileUuid}
```

#### Create Collection

Create a new collection of MCP servers.

```bash theme={null}
POST /api/collections
```

**Request Body:**

```json theme={null}
{
  "name": "My Collection",
  "description": "Collection description",
  "profileUuid": "profile-uuid",
  "serverUuids": ["server-uuid-1", "server-uuid-2"],
  "isPublic": false
}
```

#### Update Collection

Update an existing collection's metadata and server list.

```bash theme={null}
PATCH /api/collections/{collectionUuid}
```

**Request Body:**

```json theme={null}
{
  "name": "Updated Collection Name",
  "description": "Updated description",
  "serverUuids": ["server-uuid-1", "server-uuid-3"],
  "isPublic": true
}
```

#### Delete Collection

Remove a collection and its associations.

```bash theme={null}
DELETE /api/collections/{collectionUuid}
```

### Registry API

#### Submit to Registry

Submit an MCP server to the official registry.

```bash theme={null}
POST /api/registry/submit
```

**Request Body:**

```json theme={null}
{
  "repository": "https://github.com/username/repo",
  "transport": ["stdio", "sse"],
  "package_type": "npm",
  "environment_variables": ["API_KEY", "DATABASE_URL"]
}
```

**Requirements:**

* Must be authenticated with GitHub
* Must have repository ownership
* Valid package.json/Dockerfile/setup.py

#### Get Server Statistics

Get detailed statistics for a server.

```bash theme={null}
GET /api/servers/{uuid}/stats
```

**Response:**

```json theme={null}
{
  "installations": 1250,
  "rating": 4.5,
  "ratings_count": 28,
  "trending_rank": 3,
  "last_activity": "2024-01-15T10:30:00Z",
  "daily_installs": [10, 15, 20, 25, 30, 35, 40]
}
```

#### Registry Health Check

Check the status of the MCP registry.

```bash theme={null}
GET /api/registry/health
```

**Response:**

```json theme={null}
{
  "status": "healthy",
  "version": "2.0.0",
  "last_indexed": "2024-01-15T10:30:00Z",
  "total_servers": 15420
}
```

### Registry API

#### Submit to Registry

Submit an MCP server to the official registry.

```bash theme={null}
POST /api/registry/submit
```

**Request Body:**

```json theme={null}
{
  "repository": "https://github.com/username/repo",
  "transport": ["stdio", "sse"],
  "package_type": "npm",
  "environment_variables": ["API_KEY", "DATABASE_URL"]
}
```

**Requirements:**

* Must be authenticated with GitHub
* Must have repository ownership
* Valid package.json/Dockerfile/setup.py

#### Get Server Statistics

Get detailed statistics for a server.

```bash theme={null}
GET /api/servers/{uuid}/stats
```

**Response:**

```json theme={null}
{
  "installations": 1250,
  "rating": 4.5,
  "ratings_count": 28,
  "trending_rank": 3,
  "last_activity": "2024-01-15T10:30:00Z",
  "daily_installs": [10, 15, 20, 25, 30, 35, 40]
}
```

### OAuth API

#### OAuth Sessions

Get all OAuth sessions for the authenticated user.

```bash theme={null}
GET /api/mcp/oauth/session
```

**Response:**

```json theme={null}
{
  "sessions": [
    {
      "id": "session_123",
      "provider": "github",
      "created_at": "2024-01-15T10:30:00Z",
      "last_used": "2024-01-15T14:20:00Z",
      "scopes": ["repo", "user:email"]
    }
  ]
}
```

#### Create OAuth Session

Initiate a new OAuth session for MCP server authentication.

```bash theme={null}
POST /api/mcp/oauth/session
```

**Request Body:**

```json theme={null}
{
  "provider": "github",
  "redirect_uri": "https://your-app.com/oauth/callback",
  "scopes": ["repo", "user:email"]
}
```

**Response:**

```json theme={null}
{
  "authorization_url": "https://github.com/login/oauth/authorize?client_id=...&state=...",
  "session_id": "session_123"
}
```

#### OAuth Callback

Handle OAuth provider callback with authorization code.

```bash theme={null}
POST /api/mcp/oauth/callback
```

**Request Body:**

```json theme={null}
{
  "session_id": "session_123",
  "code": "authorization_code_from_provider",
  "state": "oauth_state_parameter"
}
```

**Response:**

```json theme={null}
{
  "access_token": "encrypted_access_token",
  "refresh_token": "encrypted_refresh_token",
  "expires_at": "2024-01-15T11:30:00Z"
}
```

#### Get OAuth Session

Retrieve details for a specific OAuth session.

```bash theme={null}
GET /api/mcp/oauth/session/{sessionId}
```

**Response:**

```json theme={null}
{
  "id": "session_123",
  "provider": "github",
  "status": "active",
  "created_at": "2024-01-15T10:30:00Z",
  "expires_at": "2024-01-15T11:30:00Z"
}
```

#### Delete OAuth Session

Revoke an OAuth session and associated tokens.

```bash theme={null}
DELETE /api/mcp/oauth/session/{sessionId}
```

**Response:**

```json theme={null}
{
  "success": true,
  "message": "OAuth session revoked successfully"
}
```

### User Management

#### Check Username Availability

Check if a username is available.

```bash theme={null}
GET /api/check-username?username=desired-username
```

**Response:**

```json theme={null}
{
  "available": true
}
```

#### Get User Profile

Get public user profile information.

```bash theme={null}
GET /api/users/{username}
```

**Response:**

```json theme={null}
{
  "username": "john_doe",
  "bio": "MCP enthusiast",
  "avatar_url": "https://...",
  "is_public": true,
  "followers_count": 42,
  "following_count": 23,
  "servers_count": 5
}
```

#### Update User Profile

Update the authenticated user's profile information.

```bash theme={null}
PATCH /api/users/profile
```

**Request Body:**

```json theme={null}
{
  "bio": "Updated bio",
  "is_public": true,
  "social_links": {
    "github": "https://github.com/username",
    "twitter": "https://twitter.com/username"
  }
}
```

### Notifications API

<Warning>
  All notification endpoints require authentication. Include your API key in the Authorization header.
</Warning>

#### Get Notifications

Retrieve notifications for the authenticated user.

```bash theme={null}
GET /api/notifications
```

<CodeGroup>
  ```bash cURL theme={null}
  curl "https://plugged.in/api/notifications?unread=true" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://plugged.in/api/notifications?unread=true', {
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY'
    }
  });
  const notifications = await response.json();
  ```
</CodeGroup>

**Query Parameters:**

* `unread` (boolean) - Filter unread only
* `limit` (integer) - Results per page (default: 20, max: 100)
* `offset` (integer) - Pagination offset

**Response:**

```json theme={null}
{
  "notifications": [
    {
      "id": "notif_123",
      "type": "server_installed",
      "message": "Your server 'Database Tools' was installed by user123",
      "read": false,
      "created_at": "2024-01-15T10:30:00Z",
      "metadata": {
        "server_id": "server_123",
        "user_id": "user_123"
      }
    }
  ],
  "total": 5,
  "unread_count": 3
}
```

#### Mark as Read

Mark a notification as read.

```bash theme={null}
PATCH /api/notifications/{id}/read
```

<CodeGroup>
  ```bash cURL theme={null}
  curl -X PATCH "https://plugged.in/api/notifications/notif_123/read" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://plugged.in/api/notifications/notif_123/read', {
    method: 'PATCH',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY'
    }
  });
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "success": true,
  "notification": {
    "id": "notif_123",
    "read": true,
    "read_at": "2024-01-15T10:35:00Z"
  }
}
```

#### Delete Notification

Delete a notification permanently.

```bash theme={null}
DELETE /api/notifications/{id}
```

<CodeGroup>
  ```bash cURL theme={null}
  curl -X DELETE "https://plugged.in/api/notifications/notif_123" \
    -H "Authorization: Bearer YOUR_API_KEY"
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://plugged.in/api/notifications/notif_123', {
    method: 'DELETE',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY'
    }
  });
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "success": true,
  "message": "Notification deleted successfully"
}
```

#### Send Custom Notification (MCP Tool)

This is typically called via MCP tools, but can also be used via API.

```bash theme={null}
POST /api/notifications
```

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://plugged.in/api/notifications" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "title": "Custom Alert",
      "message": "Your process completed successfully",
      "severity": "INFO",
      "send_email": false
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://plugged.in/api/notifications', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      title: 'Custom Alert',
      message: 'Your process completed successfully',
      severity: 'INFO',
      send_email: false
    })
  });
  ```
</CodeGroup>

**Request Body:**

```json theme={null}
{
  "title": "string (optional)",
  "message": "string (required)",
  "severity": "INFO | SUCCESS | WARNING | ALERT",
  "send_email": false,
  "metadata": {}
}
```

### Embedded Chat API

#### Create Chat Session

Initialize a new embedded chat session.

```bash theme={null}
POST /api/embedded-chat/sessions
```

**Request Body:**

```json theme={null}
{
  "profileUuid": "profile-uuid",
  "model": "claude-3-opus",
  "temperature": 0.7,
  "maxTokens": 4096
}
```

#### Send Message

Send a message in a chat session.

```bash theme={null}
POST /api/embedded-chat/messages
```

**Request Body:**

```json theme={null}
{
  "sessionId": "session-id",
  "message": "User message",
  "includeContext": true
}
```

## Error Handling

All API endpoints return consistent error responses:

```json theme={null}
{
  "error": {
    "code": "ERROR_CODE",
    "message": "Human-readable error message",
    "details": {
      "field": "Additional context"
    }
  }
}
```

### Common Error Codes

| Code               | Status | Description                       |
| ------------------ | ------ | --------------------------------- |
| `UNAUTHORIZED`     | 401    | Missing or invalid authentication |
| `FORBIDDEN`        | 403    | Insufficient permissions          |
| `NOT_FOUND`        | 404    | Resource not found                |
| `RATE_LIMITED`     | 429    | Rate limit exceeded               |
| `VALIDATION_ERROR` | 400    | Invalid request parameters        |
| `SERVER_ERROR`     | 500    | Internal server error             |

## Webhooks

<Warning>
  **Authentication Required:** Webhook configuration and management requires authentication. Webhook payloads include a signature for verification.
</Warning>

Configure webhooks to receive real-time notifications about events in your Plugged.in account.

### Setting Up Webhooks

#### Register a Webhook Endpoint

```bash theme={null}
POST /api/webhooks
```

<CodeGroup>
  ```bash cURL theme={null}
  curl -X POST "https://plugged.in/api/webhooks" \
    -H "Authorization: Bearer YOUR_API_KEY" \
    -H "Content-Type: application/json" \
    -d '{
      "url": "https://your-app.com/webhook",
      "events": ["server.installed", "document.created"],
      "active": true,
      "secret": "your-webhook-secret"
    }'
  ```

  ```javascript JavaScript theme={null}
  const response = await fetch('https://plugged.in/api/webhooks', {
    method: 'POST',
    headers: {
      'Authorization': 'Bearer YOUR_API_KEY',
      'Content-Type': 'application/json'
    },
    body: JSON.stringify({
      url: 'https://your-app.com/webhook',
      events: ['server.installed', 'document.created'],
      active: true,
      secret: 'your-webhook-secret'
    })
  });
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "id": "webhook_123",
  "url": "https://your-app.com/webhook",
  "events": ["server.installed", "document.created"],
  "active": true,
  "created_at": "2024-01-15T10:30:00Z"
}
```

#### List Webhooks

```bash theme={null}
GET /api/webhooks
```

```bash theme={null}
curl "https://plugged.in/api/webhooks" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

#### Update Webhook

```bash theme={null}
PATCH /api/webhooks/{webhook_id}
```

```bash theme={null}
curl -X PATCH "https://plugged.in/api/webhooks/webhook_123" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "active": false
  }'
```

#### Delete Webhook

```bash theme={null}
DELETE /api/webhooks/{webhook_id}
```

```bash theme={null}
curl -X DELETE "https://plugged.in/api/webhooks/webhook_123" \
  -H "Authorization: Bearer YOUR_API_KEY"
```

### Webhook Security

#### Signature Verification

All webhook payloads include a signature in the `X-Pluggedin-Signature` header for verification:

```javascript theme={null}
const crypto = require('crypto');

function verifyWebhookSignature(payload, signature, secret) {
  const expectedSignature = crypto
    .createHmac('sha256', secret)
    .update(JSON.stringify(payload))
    .digest('hex');

  return crypto.timingSafeEqual(
    Buffer.from(signature),
    Buffer.from(expectedSignature)
  );
}

// In your webhook handler
app.post('/webhook', (req, res) => {
  const signature = req.headers['x-pluggedin-signature'];
  const secret = process.env.WEBHOOK_SECRET;

  if (!verifyWebhookSignature(req.body, signature, secret)) {
    return res.status(401).send('Invalid signature');
  }

  // Process webhook
  handleWebhook(req.body);
  res.status(200).send('OK');
});
```

### Supported Events

| Event                  | Description                  | Payload                   |
| ---------------------- | ---------------------------- | ------------------------- |
| `server.installed`     | MCP server installed         | Server UUID, User ID      |
| `server.uninstalled`   | MCP server removed           | Server UUID, User ID      |
| `server.updated`       | Server configuration changed | Server UUID, Changes      |
| `document.created`     | Document added to library    | Document ID, Profile UUID |
| `document.deleted`     | Document removed             | Document ID               |
| `collection.shared`    | Collection made public       | Collection UUID           |
| `collection.updated`   | Collection modified          | Collection UUID, Changes  |
| `user.followed`        | User gained a follower       | Follower ID, Followed ID  |
| `user.unfollowed`      | User lost a follower         | Follower ID, Followed ID  |
| `notification.created` | New notification             | Notification ID, Type     |

### Webhook Payload Format

```json theme={null}
{
  "id": "evt_123",
  "event": "server.installed",
  "timestamp": "2024-01-15T10:30:00Z",
  "signature": "sha256=abc123...",
  "data": {
    "server_uuid": "123e4567-e89b-12d3-a456-426614174000",
    "user_id": "user-123",
    "profile_uuid": "profile-456",
    "metadata": {
      "source": "registry",
      "version": "1.0.0"
    }
  },
  "retry_count": 0
}
```

### Webhook Retry Policy

Failed webhook deliveries are retried with exponential backoff:

* **1st retry**: After 1 minute
* **2nd retry**: After 5 minutes
* **3rd retry**: After 30 minutes
* **4th retry**: After 2 hours
* **5th retry**: After 12 hours

After 5 failed attempts, the webhook is marked as failed and no further retries are attempted.

### Testing Webhooks

#### Test Webhook Endpoint

Send a test event to your webhook:

```bash theme={null}
POST /api/webhooks/{webhook_id}/test
```

```bash theme={null}
curl -X POST "https://plugged.in/api/webhooks/webhook_123/test" \
  -H "Authorization: Bearer YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{
    "event": "test.ping"
  }'
```

### Analytics API

#### Get Trending Servers

Retrieve trending MCP servers based on activity and popularity.

```bash theme={null}
GET /api/trending/servers
```

**Query Parameters:**

* `limit` (integer) - Number of results (default: 20, max: 100)
* `timeframe` (string) - Time period: `day`, `week`, `month` (default: week)
* `category` (string) - Filter by category

**Response:**

```json theme={null}
{
  "servers": [
    {
      "uuid": "server_123",
      "name": "Database Tools",
      "slug": "database-tools",
      "installation_count": 1250,
      "rating": 4.5,
      "trending_score": 95.2,
      "rank_change": "+5",
      "category": "database"
    }
  ],
  "total": 150,
  "timeframe": "week"
}
```

#### Get Service Search Statistics

Get search analytics for service discovery.

```bash theme={null}
GET /api/service/search
```

**Query Parameters:**

* `q` (string) - Search query to analyze
* `timeframe` (string) - Analysis period: `day`, `week`, `month`

**Response:**

```json theme={null}
{
  "query": "database",
  "total_searches": 1250,
  "unique_users": 89,
  "top_results": [
    {
      "server_uuid": "server_123",
      "clicks": 45,
      "impressions": 120,
      "ctr": 0.375
    }
  ],
  "related_queries": ["postgres", "mysql", "mongodb"]
}
```

### Maintenance & Cron Jobs

#### OAuth PKCE State Cleanup

<Info>
  This endpoint is designed for external cron jobs to periodically clean up expired OAuth PKCE states. The cleanup also runs automatically in-process, so external cron is optional but recommended for production.
</Info>

Clean up expired OAuth PKCE states to prevent database bloat and ensure security.

**Endpoint:** `POST /api/oauth/cleanup-pkce`

**Authentication:** Requires `CRON_SECRET` in Authorization header

**Recommended Schedule:** Every 10-15 minutes

<CodeGroup>
  ```bash curl theme={null}
  curl -X POST https://your-domain.com/api/oauth/cleanup-pkce \
    -H "Authorization: Bearer YOUR_CRON_SECRET"
  ```

  ```javascript Node.js theme={null}
  const response = await fetch('https://your-domain.com/api/oauth/cleanup-pkce', {
    method: 'POST',
    headers: {
      'Authorization': `Bearer ${process.env.CRON_SECRET}`
    }
  });

  const result = await response.json();
  console.log(`Cleaned up ${result.deletedCount} expired states`);
  ```

  ```python Python theme={null}
  import requests
  import os

  response = requests.post(
      'https://your-domain.com/api/oauth/cleanup-pkce',
      headers={'Authorization': f'Bearer {os.getenv("CRON_SECRET")}'}
  )

  result = response.json()
  print(f"Cleaned up {result['deletedCount']} expired states")
  ```
</CodeGroup>

**Response:**

```json theme={null}
{
  "success": true,
  "deletedCount": 5,
  "message": "Cleaned up 5 expired PKCE states",
  "timestamp": "2025-01-09T12:00:00.000Z"
}
```

**Development Testing:**

In development, you can use GET without authentication:

```bash theme={null}
# Only works in development (NODE_ENV !== 'production')
curl http://localhost:12005/api/oauth/cleanup-pkce
```

<Warning>
  **Production Security:**

  GET method is disabled in production for security. Always use POST with Bearer token authentication in production environments.
</Warning>

**Cron Configuration Examples:**

<Tabs>
  <Tab title="GitHub Actions">
    ```yaml theme={null}
    name: OAuth PKCE Cleanup
    on:
      schedule:
        - cron: '*/10 * * * *'  # Every 10 minutes

    jobs:
      cleanup:
        runs-on: ubuntu-latest
        steps:
          - name: Trigger cleanup
            run: |
              curl -X POST ${{ secrets.APP_URL }}/api/oauth/cleanup-pkce \
                -H "Authorization: Bearer ${{ secrets.CRON_SECRET }}"
    ```
  </Tab>

  <Tab title="Vercel Cron">
    ```json vercel.json theme={null}
    {
      "crons": [{
        "path": "/api/oauth/cleanup-pkce",
        "schedule": "*/10 * * * *"
      }]
    }
    ```
  </Tab>

  <Tab title="Linux Crontab">
    ```bash theme={null}
    # Add to crontab (crontab -e)
    */10 * * * * curl -X POST https://your-domain.com/api/oauth/cleanup-pkce \
      -H "Authorization: Bearer YOUR_CRON_SECRET" >> /var/log/pluggedin-cron.log 2>&1
    ```
  </Tab>
</Tabs>

<Note>
  See the [Maintenance Guide](/deployment/maintenance) for complete setup instructions and best practices.
</Note>

### Webhook Best Practices

<AccordionGroup>
  <Accordion title="Always Verify Signatures">
    Never process webhooks without verifying the signature to ensure they're from Plugged.in.
  </Accordion>

  <Accordion title="Respond Quickly">
    Return a 2xx status code within 5 seconds. Process webhook data asynchronously if needed.

    ```javascript theme={null}
    app.post('/webhook', (req, res) => {
      // Respond immediately
      res.status(200).send('OK');

      // Process asynchronously
      processWebhookAsync(req.body);
    });
    ```
  </Accordion>

  <Accordion title="Handle Duplicates">
    Use the event ID to handle potential duplicate deliveries:

    ```javascript theme={null}
    const processedEvents = new Set();

    function handleWebhook(payload) {
      if (processedEvents.has(payload.id)) {
        return; // Already processed
      }
      processedEvents.add(payload.id);
      // Process event
    }
    ```
  </Accordion>

  <Accordion title="Monitor Webhook Health">
    Check webhook delivery status regularly:

    ```bash theme={null}
    GET /api/webhooks/{webhook_id}/deliveries
    ```
  </Accordion>
</AccordionGroup>

## Support

* **Documentation**: [docs.plugged.in](https://docs.plugged.in)
* **GitHub Issues**: [Report bugs](https://github.com/VeriTeknik/pluggedin-app/issues)
* **Email Support**: [api-support@plugged.in](mailto:api-support@plugged.in)
