# How the Built-in API Server in Cherry Studio Works: Architecture and Implementation Guide

> Explore the architecture and implementation of Cherry Studio's built-in API server. Learn how this Express-based server enhances your LLM workflows with OpenAI-compatible endpoints.

- Repository: [CherryHQ/cherry-studio](https://github.com/cherryhq/cherry-studio)
- Tags: architecture
- Published: 2026-02-27

---

**Cherry Studio's built-in API server is an Express-based HTTP API that runs inside the Electron main process, exposing OpenAI-compatible endpoints for model listing, chat completions, and Anthropic-style message streaming while authenticating requests against user-configured LLM providers.**

The built-in API server in Cherry Studio enables external clients and the React renderer to interact with configured LLM providers through a unified REST interface. Running directly within the Electron main process, this lightweight server shares the Redux state and logging services with the desktop UI, ensuring provider configurations remain synchronized between the graphical interface and API consumers.

## High-Level Architecture

The server follows a layered Express architecture defined in [`src/main/apiServer/app.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/apiServer/app.ts). This bootstrap file initializes the application, configures global middleware, mounts route handlers, and starts the HTTP listener on a random available port.

### Core Layers

- **Server bootstrap** ([`src/main/apiServer/app.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/apiServer/app.ts)): Creates the Express instance, enables JSON parsing and CORS, adds request-ID headers, and mounts versioned routes under `/v1/*` alongside health endpoints and OpenAPI documentation.

- **Middleware stack** (`src/main/apiServer/middleware/`):
  - **`authMiddleware`** ([`auth.ts`](https://github.com/cherryhq/cherry-studio/blob/main/auth.ts)): Validates the `Authorization` header against API keys stored for configured providers.
  - **`errorHandler`** ([`error.ts`](https://github.com/cherryhq/cherry-studio/blob/main/error.ts)): Catches synchronous and asynchronous errors, formatting them into uniform JSON error objects with `type`, `message`, and `code` properties.
  - **Timeout extension**: `extendMessagesTimeout` raises request timeouts for long-running streaming calls.

- **Routing layer** (`src/main/apiServer/routes/`): Dedicated routers handle **models**, **chat**, **messages**, **MCP**, and **agents**, each validating inputs with Zod schemas before delegating to services.

- **Service layer** (`src/main/apiServer/services/`):
  - **ModelsService** ([`models.ts`](https://github.com/cherryhq/cherry-studio/blob/main/models.ts)): Aggregates available models from all providers, handles deduplication, and applies pagination.
  - **ChatCompletionService** ([`chat-completion.ts`](https://github.com/cherryhq/cherry-studio/blob/main/chat-completion.ts)): Builds OpenAI-compatible requests and manages streaming via Server-Sent Events (SSE).
  - **MessagesService** ([`messages.ts`](https://github.com/cherryhq/cherry-studio/blob/main/messages.ts)): Handles Anthropic endpoint communication with request validation and SSE streaming.

- **Provider utilities** ([`src/main/apiServer/utils/index.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/apiServer/utils/index.ts)): Shared helpers for reading the Redux store (`getAvailableProviders`), parsing model IDs in `providerId:modelId` format, and caching provider lists.

### Request Flow Example

A `POST /v1/chat/completions` request flows through the following pipeline:

1. Express receives the request and applies CORS and JSON parsing middleware.
2. `authMiddleware` verifies the bearer token against stored provider configurations.
3. The `chatRoutes` router validates the payload schema and calls `chatCompletionService.processCompletion` (or `processStreamingCompletion` when `stream: true`).
4. The service builds a provider-specific request using the OpenAI SDK client and returns either a JSON response or SSE chunks.
5. Any thrown errors bubble to `errorHandler`, which serializes them into standard JSON error responses.

## Authentication and Security

The `authMiddleware` in [`src/main/apiServer/middleware/auth.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/apiServer/middleware/auth.ts) guards all endpoints by validating the `Authorization` header against the API keys stored for each configured LLM provider in the Redux store. This ensures that external clients must present valid credentials matching the user's desktop application configuration before accessing model inference capabilities.

## Core Endpoints and Services

### Model Listing (GET /v1/models)

The models endpoint in [`src/main/apiServer/routes/models.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/apiServer/routes/models.ts) delegates to `ModelsService.getModels`, which retrieves enabled providers from Redux via `getAvailableProviders` and transforms each model using `transformModelToOpenAI` in [`src/main/apiServer/utils/index.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/apiServer/utils/index.ts). The response follows the OpenAI list format with pagination support via `limit` and `offset` query parameters.

**Key function:** `transformModelToOpenAI` maps internal provider metadata to OpenAI-compatible model objects including `id`, `owned_by`, and provider-specific fields.

### Chat Completions (POST /v1/chat/completions)

Located in [`src/main/apiServer/routes/chat.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/apiServer/routes/chat.ts), this endpoint accepts OpenAI-compatible request bodies containing `model`, `messages`, and optional `stream` parameters.

**Non-streaming flow:** The route calls `chatCompletionService.processCompletion`, which instantiates an OpenAI SDK client via `openaiService.getClient` and returns the complete JSON response.

**Streaming flow:** When `stream: true`, the service calls `processStreamingCompletion`, which writes SSE chunks (`data:` lines) to the response using `res.write()` and flushes after each chunk to maintain real-time delivery.

### Anthropic Messages (POST /v1/messages)

The messages router in [`src/main/apiServer/routes/messages.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/apiServer/routes/messages.ts) exposes Anthropic-style endpoints for compatibility with Claude-specific integrations. The `MessagesService.handleStreaming` method manages SSE streaming for these requests, writing `event:` and `data:` formatted chunks that match the Anthropic streaming contract while abstracting provider-specific implementation details.

## Implementation Examples

### Starting the Server

The Electron main process initializes the server in [`main.ts`](https://github.com/cherryhq/cherry-studio/blob/main/main.ts) using a random port:

```typescript
import { app as apiApp } from './src/main/apiServer/app';

const server = apiApp.listen(0, () => {
  const address = server.address() as any;
  logger.info('Cherry Studio API server listening', { port: address.port });
});

```

Port `0` instructs the operating system to assign a random free port, which the application logs for client consumption.

### Listing Available Models

```bash
curl -H "Authorization: Bearer <API_KEY>" \
     "http://localhost:PORT/v1/models?providerType=anthropic&limit=10&offset=0"

```

**Response structure:**

```json
{
  "object": "list",
  "data": [
    {
      "id": "anthropic:claude-3-5-sonnet-20241022",
      "object": "model",
      "name": "Claude 3.5 Sonnet",
      "created": 1700000000,
      "owned_by": "anthropic",
      "provider": "anthropic",
      "provider_name": "Anthropic",
      "provider_type": "anthropic",
      "provider_model_id": "claude-3-5-sonnet-20241022"
    }
  ],
  "total": 12,
  "offset": 0,
  "limit": 10
}

```

### Non-Streaming Chat Completion

```bash
curl -X POST -H "Content-Type: application/json" \
     -H "Authorization: Bearer <API_KEY>" \
     -d '{
           "model":"openai:gpt-4o-mini",
           "messages":[{"role":"user","content":"Explain quantum tunnelling"}],
           "max_tokens":256
         }' \
     http://localhost:PORT/v1/chat/completions

```

### Streaming Anthropic Messages

```bash
curl -N -H "Authorization: Bearer <API_KEY>" \
     -H "Accept: text/event-stream" \
     -d '{
           "model":"anthropic:claude-3-5-sonnet-20241022",
           "messages":[{"role":"user","content":"Write a haiku about sunrise"}],
           "stream":true
         }' \
     http://localhost:PORT/v1/messages

```

The `-N` flag disables buffering to display SSE chunks in real-time as `MessagesService.handleStreaming` writes them to the response.

## Key Source Files

The following files implement the core API server functionality in the `cherryhq/cherry-studio` repository:

- **[`src/main/apiServer/app.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/apiServer/app.ts)** – Express application bootstrap, global middleware configuration, and server initialization.
- **[`src/main/apiServer/middleware/auth.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/apiServer/middleware/auth.ts)** – API key validation against configured providers.
- **[`src/main/apiServer/middleware/error.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/apiServer/middleware/error.ts)** – Centralized error handling and JSON response formatting.
- **[`src/main/apiServer/routes/models.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/apiServer/routes/models.ts)** – `GET /v1/models` endpoint implementation.
- **[`src/main/apiServer/routes/chat.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/apiServer/routes/chat.ts)** – `POST /v1/chat/completions` with streaming support.
- **[`src/main/apiServer/routes/messages.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/apiServer/routes/messages.ts)** – `POST /v1/messages` Anthropic-compatible endpoint.
- **[`src/main/apiServer/services/models.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/apiServer/services/models.ts)** – Model aggregation and deduplication logic.
- **[`src/main/apiServer/services/chat-completion.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/apiServer/services/chat-completion.ts)** – OpenAI client management and streaming implementation.
- **[`src/main/apiServer/services/messages.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/apiServer/services/messages.ts)** – Anthropic client handling and SSE streaming.
- **[`src/main/apiServer/utils/index.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/apiServer/utils/index.ts)** – Provider resolution, model ID parsing (`providerId:modelId`), and caching utilities.
- **[`src/main/services/LoggerService.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/services/LoggerService.ts)** – Central logging service used throughout the API server with `"ApiServer"` context.

## Summary

Cherry Studio's built-in API server provides a production-ready HTTP interface for LLM interactions:

- Runs as an **Express application inside the Electron main process**, sharing Redux state with the desktop UI.
- Exposes **OpenAI-compatible endpoints** (`/v1/models`, `/v1/chat/completions`) and **Anthropic-compatible endpoints** (`/v1/messages`) with uniform authentication.
- Validates requests through `authMiddleware` against stored provider API keys and uses `errorHandler` for consistent error formatting.
- Delegates to specialized service classes (`ChatCompletionService`, `MessagesService`) that handle provider-specific SDK integration and SSE streaming.
- Supports both synchronous JSON responses and real-time streaming via Server-Sent Events for compatible clients.

External tools, scripts, or integrations can interact with Cherry Studio exactly as they would with hosted OpenAI or Anthropic services, while the desktop application maintains full control over provider configuration and API key management.

## Frequently Asked Questions

### What port does the Cherry Studio API server use?

The server binds to port `0` (random available port) when started from the Electron main process. The actual port number is logged at startup and can be retrieved programmatically from the server address object, allowing external clients to discover the endpoint dynamically.

### How does the API server authenticate incoming requests?

The `authMiddleware` in [`src/main/apiServer/middleware/auth.ts`](https://github.com/cherryhq/cherry-studio/blob/main/src/main/apiServer/middleware/auth.ts) validates the `Authorization` header bearer token against the API keys stored for each configured LLM provider in the Redux store. Requests must present credentials matching one of the user's configured providers to proceed.

### Can I use the Cherry Studio API server with OpenAI-compatible SDKs?

Yes. The server implements the standard OpenAI REST API contract for model listing and chat completions, including SSE streaming support. You can point OpenAI client libraries to `http://localhost:PORT/v1` using your Cherry Studio API key to interact with configured providers transparently.

### How does streaming work for chat completions?

When `stream: true` is specified in the request body, `ChatCompletionService.processStreamingCompletion` writes Server-Sent Events (SSE) formatted chunks (`data:` JSON objects) to the HTTP response, flushing each chunk immediately. This matches the OpenAI streaming contract and allows real-time token delivery to clients.