> ## Documentation Index
> Fetch the complete documentation index at: https://dev-doc.dualmindlab.tech/llms.txt
> Use this file to discover all available pages before exploring further.

# GET /api/models

> List all active AI models

## Authentication

**Required**: JWT Bearer token

## Response

<ResponseField name="items" type="array">
  Array of active model objects

  <Expandable title="Model object">
    <ResponseField name="modelId" type="string">
      Model UUID
    </ResponseField>

    <ResponseField name="modelName" type="string">
      Model identifier (e.g., `llama-3.3-70b-versatile`)
    </ResponseField>

    <ResponseField name="displayName" type="string">
      Human-readable model name

      **Fallback** (Line 39): Uses `description` field if available, otherwise `modelName`
    </ResponseField>

    <ResponseField name="provider_name" type="string">
      Provider name (`groq`, `bytez`, etc.)
    </ResponseField>

    <ResponseField name="apiUrl" type="string">
      Provider API endpoint URL
    </ResponseField>

    <ResponseField name="status" type="string">
      Always `"active"` (due to filter)
    </ResponseField>
  </Expandable>
</ResponseField>

<RequestExample>
  ```bash cURL theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  curl -X GET 'http://localhost:5079/api/models' \
    -H 'Authorization: Bearer YOUR_JWT_TOKEN'
  ```

  ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  const response = await fetch('http://localhost:5079/api/models', {
    headers: {
      'Authorization': `Bearer ${jwt}`
    }
  });

  const models = await response.json();
  ```

  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  import requests

  response = requests.get(
      'http://localhost:5079/api/models',
      headers={'Authorization': f'Bearer {jwt}'}
  )

  models = response.json()
  ```
</RequestExample>

<ResponseExample>
  ```json 200 Success theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  {
    "items": [
      {
        "modelId": "model-uuid-1",
        "modelName": "llama-3.3-70b-versatile",
        "displayName": "Llama 3.3 70B Versatile",
        "providerName": "groq",
        "apiUrl": "https://api.groq.com/openai/v1/chat/completions",
        "status": "active"
      },
      {
        "modelId": "model-uuid-2",
        "modelName": "mixtral-8x7b-32768",
        "displayName": "Mixtral 8x7B",
        "providerName": "groq",
        "apiUrl": "https://api.groq.com/openai/v1/chat/completions",
        "status": "active"
      }
    ]
  }
  ```

  ```json 401 Unauthorized theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  {
    "error": "Unauthorized"
  }
  ```

  ```json 500 MODELS_ERROR theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
  {
    "success": false,
    "error": "Database query failed",
    "code": "MODELS_ERROR"
  }
  ```
</ResponseExample>

## Side Effects

**Database Reads** (Lines 29-33):

```csharp theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
var rows = await _supabase.SelectAsync<JObject>(
    "ai_models",
    "model_id,model_name,provider_name,api_url,description,status,created_at",
    "status=eq.active&order=created_at.desc"
);
```

**Tables Read**:

* `ai_models` table

**Filter Applied** (Line 32):

* `WHERE status = 'active'`
* `ORDER BY created_at DESC`

**No Database Writes**: Read-only endpoint

## Authorization

**Authentication**: Required (JWT Bearer)

**Who Can Read**:

* Any authenticated user

**Data Visibility**:

* Global model list (not user-specific)
* All users see same models

## Permissions

**No User Filtering**: All authenticated users see same data

**No Privacy Controls**: All active model data visible to authenticated users

## Response Structure

**Ordering** (Line 32):

* Ordered by `created_at DESC` (newest models first)
* Hardcoded in query, not configurable

**Filtering** (Line 32):

* Only `status = 'active'` models returned
* Inactive models excluded
* No additional filtering parameters

**Pagination**: Not supported

* Returns ALL active models
* Performance depends on number of active models

## Edge Cases

1. **No active models**: Returns `{"items": []}` (empty array, Line 35)
2. **Model missing description**: displayName falls back to modelName (Line 39)
3. **Null fields**: Converted to null in JSON response (Lines 37-42)
4. **Very large result set**: No pagination, could be slow

## Error Conditions

| Code           | HTTP | Cause                     | Controller Line |
| -------------- | ---- | ------------------------- | --------------- |
| N/A            | 401  | JWT missing or invalid    | Middleware      |
| `MODELS_ERROR` | 500  | Database query failure    | 47-55           |
| `MODELS_ERROR` | 500  | Supabase connection error | 47-55           |

**Exception Handling** (Lines 47-55):

```csharp theme={"theme":{"light":"github-light","dark":"github-dark-dimmed"}}
catch (Exception ex) {
    return StatusCode(500, new { error = ex.Message, code = "MODELS_ERROR" });
}
```

* All exceptions return 500
* Exception message exposed to client

## Field Mapping

**Column → Response Mapping** (Lines 35-43):

```
ai_models.model_id → modelId
ai_models.model_name → modelName
ai_models.description → displayName (fallback: model_name)
ai_models.provider_name → providerName
ai_models.api_url → apiUrl
ai_models.status → status
```

**created\_at**: Selected from database (Line 31) but NOT included in response (Lines 37-42)

## Behavioral Guarantees

**Data Staleness**: Not specified by API contract

* Caching behavior not enforced by server contract
* Real-time database query (no caching documented in controller)

**Consistency**: Not guaranteed

* Models added/removed during request processing may not be reflected

**Completeness**: All active models returned

* Partial results not enforced by server contract

## Performance Characteristics

**Query Complexity**: Simple SELECT with WHERE and ORDER BY

**Index Requirements**:

* `ai_models.status` should be indexed
* `ai_models.created_at` should be indexed for sorting

**Response Size**: Unbounded (proportional to number of active models)

**No Rate Limiting**: Not documented in controller

## Use Cases

**Model Selection**:

* Populate model dropdown in UI
* `GetRandomModelAsync` service queries this data
* `GetTwoRandomModelsAsync` for dual-chat

**Configuration**:

* Determine available providers
* Get API endpoints for model routing

**Display**:

* Show model names and descriptions to users

## Status Values

**Filtered Value**: `"active"` (Line 32)

**Other Possible Values** (not returned):

* `"inactive"`: Models disabled/deprecated
* `"testing"`: Models in beta
* Behavior not enforced by server contract (database schema-dependent)

## Provider Information

**apiUrl Field** (Line 41):

* Full provider API endpoint
* Used by chat providers for routing
* Exposed to authenticated clients

**Security**: API URLs visible to all authenticated users
