# API Reference

Complete reference for all methods in the Concentriq LS Python Client.

## Client

### ConcentriqClient

Main client class for accessing all API versions.

```python
from concentriq import ConcentriqClient
from concentriq.auth import ApiKeyAuth

client = ConcentriqClient(
    base_url: str,           # Base URL (e.g., "https://app.concentriq.com")
    auth: AuthHandler,       # Authentication handler
    timeout: float = 30.0    # Request timeout in seconds (optional)
)
```

**Properties:**
- `client.v1` - V1 API namespace
- `client.v2` - V2 API namespace
- `client.v3` - V3 API namespace

**Methods:**
- `client.close()` - Close HTTP connections
- `with client:` - Context manager support

---

## V1 API Reference

All V1 resources are accessed via `client.v1.<resource>`.

### ImageSets

**`client.v1.image_sets`**

#### list()
List image sets with pagination and filtering.

```python
client.v1.image_sets.list(
    page: int = 1,                    # Page number (1-indexed)
    limit: int = 20,                  # Items per page
    filters: ImageSetFilters = None   # Filter criteria
) -> dict
```

Returns: `{"data": [...], "meta": {...}}`

#### get()
Get a single image set by ID.

```python
client.v1.image_sets.get(id: int) -> dict
```

#### create()
Create a new image set.

```python
client.v1.image_sets.create(data: dict) -> dict
```

Required fields:
- `name` (str): Image set name

#### update()
Update an existing image set.

```python
client.v1.image_sets.update(id: int, data: dict) -> dict
```

#### delete()
Delete an image set.

```python
client.v1.image_sets.delete(id: int) -> None
```

---

### Images

**`client.v1.images`**

#### list()
List images with pagination and filtering.

```python
client.v1.images.list(
    page: int = 1,
    limit: int = 20,
    filters: ImageFilters = None
) -> dict
```

#### get()
Get a single image by ID.

```python
client.v1.images.get(id: int) -> dict
```

#### download()
Get signed S3 URL for image file download.

```python
client.v1.images.download(id: int) -> dict
```

Returns: `{"url": "https://...", "expiresAt": "..."}`

---

### Folders

**`client.v1.folders`**

#### list()
List folders with pagination and filtering.

```python
client.v1.folders.list(
    page: int = 1,
    limit: int = 20,
    filters: FolderFilters = None
) -> dict
```

#### get()
Get a single folder by ID.

```python
client.v1.folders.get(id: int) -> dict
```

#### create()
Create a new folder.

```python
client.v1.folders.create(data: dict) -> dict
```

Required fields:
- `imageSetId` (int): Parent image set ID
- `name` (str): Folder name

#### update()
Update an existing folder.

```python
client.v1.folders.update(id: int, data: dict) -> dict
```

#### delete()
Delete a folder.

```python
client.v1.folders.delete(id: int) -> None
```

---

### Annotations

**`client.v1.annotations`**

#### list()
List annotations with pagination and filtering.

```python
client.v1.annotations.list(
    page: int = 1,
    limit: int = 20,
    filters: AnnotationFilters = None
) -> dict
```

#### get()
Get a single annotation by ID.

```python
client.v1.annotations.get(id: int) -> dict
```

#### create()
Create a new annotation.

```python
client.v1.annotations.create(data: dict) -> dict
```

Required fields:
- `imageId` (int): Parent image ID
- `annotationClassId` (int): Annotation class/type
- `geometry` (dict): Annotation shape and coordinates

#### update()
Update an existing annotation.

```python
client.v1.annotations.update(id: int, data: dict) -> dict
```

#### delete()
Delete an annotation.

```python
client.v1.annotations.delete(id: int) -> None
```

---

### Metadata

**`client.v1.metadata.fields`**

#### list()
List metadata field definitions.

```python
client.v1.metadata.fields.list(
    page: int = 1,
    limit: int = 20
) -> dict
```

#### get()
Get a single metadata field by ID.

```python
client.v1.metadata.fields.get(id: int) -> dict
```

#### create()
Create a new metadata field.

```python
client.v1.metadata.fields.create(data: dict) -> dict
```

Required fields:
- `name` (str): Field name
- `type` (str): Field type (text, number, date, etc.)

#### update()
Update a metadata field.

```python
client.v1.metadata.fields.update(id: int, data: dict) -> dict
```

#### delete()
Delete a metadata field.

```python
client.v1.metadata.fields.delete(id: int) -> None
```

**`client.v1.metadata.values`**

#### list()
List metadata values with filtering.

```python
client.v1.metadata.values.list(
    filters: MetadataValueFilters = None
) -> dict
```

#### update()
Batch update metadata values for a resource.

```python
client.v1.metadata.values.update(data: dict) -> dict
```

Required fields:
- `resourceId` (int): Resource ID
- `resourceType` (str): Resource type (ImageSet, Image, Folder, Annotation)
- `values` (dict): Key-value pairs of metadata

---

### Other V1 Resources

**Users** - `client.v1.users`
- `list(page, limit)` - List users
- `create(data)` - Create user
- `update(id, data)` - Update user

**Organizations** - `client.v1.organizations`
- `list()` - List organizations
- `get(id)` - Get organization

**Templates** - `client.v1.templates`
- `list(page, limit)` - List templates
- `get(id)` - Get template
- `create(data)` - Create template
- `update(id, data)` - Update template
- `delete(id)` - Delete template

**Workflows** - `client.v1.workflows`
- `list(filters)` - List workflows
- `create(data)` - Create workflow (admin only)
- `update(id, data)` - Update workflow (admin only)
- `delete(id)` - Delete workflow (admin only)

**Orders** - `client.v1.orders`
- `list_stains()` - Get available stains
- `list(filters)` - List orders
- `create(data)` - Create order

**Attachments** - `client.v1.attachments`
- `list(filters)` - List attachments
- `create(data)` - Create attachment (returns S3 storage key)
- `delete(id)` - Delete attachment

---

## V2 API Reference

All V2 resources are accessed via `client.v2.<resource>`.

### UserGroups

**`client.v2.user_groups`**

#### list()
```python
client.v2.user_groups.list(page: int = 1, limit: int = 20, filters: dict = None) -> dict
```

#### get()
```python
client.v2.user_groups.get(id: int) -> dict
```

#### create()
```python
client.v2.user_groups.create(data: dict) -> dict
```

Requires `canManageGroups` permission.

#### update()
```python
client.v2.user_groups.update(id: int, data: dict) -> dict
```

#### delete()
```python
client.v2.user_groups.delete(id: int) -> None
```

---

### Modules

**`client.v2.modules`**

#### list()
```python
client.v2.modules.list(page: int = 1, limit: int = 20) -> dict
```

#### get()
```python
client.v2.modules.get(id: int) -> dict
```

#### create()
```python
client.v2.modules.create(data: dict) -> dict
```

#### update()
```python
client.v2.modules.update(id: int, data: dict) -> dict
```

#### delete()
```python
client.v2.modules.delete(id: int) -> None
```

---

### SavedDisplaySettings

**`client.v2.saved_display_settings`**

Manage fluorescence image display settings.

#### list()
```python
client.v2.saved_display_settings.list(page: int = 1, limit: int = 20) -> dict
```

#### get()
```python
client.v2.saved_display_settings.get(id: int) -> dict
```

#### create()
```python
client.v2.saved_display_settings.create(data: dict) -> dict
```

#### update()
```python
client.v2.saved_display_settings.update(id: int, data: dict) -> dict
```

#### delete()
```python
client.v2.saved_display_settings.delete(id: int) -> None
```

---

## V3 API Reference

All V3 resources are accessed via `client.v3.<resource>`.

### Auth

**`client.v3.auth`**

#### whoami()
Get current user information and permissions.

```python
client.v3.auth.whoami() -> dict
```

Returns: `{"userId": int, "roleRules": [...]}`

#### get_public_key()
Get JWT public key for token verification.

```python
client.v3.auth.get_public_key() -> dict
```

#### create_token()
Create a JWT bearer token.

```python
client.v3.auth.create_token() -> dict
```

Returns: `{"token": "eyJhbGci..."}`

#### create_api_key()
Generate a new API key.

```python
client.v3.auth.create_api_key() -> dict
```

Returns: `{"apiKey": "..."}`

#### delete_api_key()
Delete the current API key.

```python
client.v3.auth.delete_api_key() -> None
```

#### check_api_key_status()
Check if current API key is active.

```python
client.v3.auth.check_api_key_status() -> dict
```

Returns: `{"active": bool}`

---

### Studies

**`client.v3.studies`**

#### list()
```python
client.v3.studies.list() -> dict
```

#### get()
```python
client.v3.studies.get(id: int) -> dict
```

#### create()
```python
client.v3.studies.create(data: dict) -> dict
```

#### update()
```python
client.v3.studies.update(id: int, data: dict) -> dict
```

#### delete()
```python
client.v3.studies.delete(id: int) -> None
```

#### get_fields()
Get fields in use by the study.

```python
client.v3.studies.get_fields(study_id: int) -> list
```

#### add_field()
Add a field to the study.

```python
client.v3.studies.add_field(study_id: int, field_id: int) -> None
```

#### remove_field()
Remove a field from the study.

```python
client.v3.studies.remove_field(study_id: int, field_id: int) -> None
```

#### get_users()
Get users in the study.

```python
client.v3.studies.get_users(study_id: int) -> list
```

#### upsert_user()
Add or update a user in the study.

```python
client.v3.studies.upsert_user(study_id: int, user_id: int, data: dict) -> dict
```

#### remove_user()
Remove a user from the study.

```python
client.v3.studies.remove_user(study_id: int, user_id: int) -> None
```

#### get_statistics()
Get study statistics.

```python
client.v3.studies.get_statistics(study_id: int) -> list
```

---

### ImageSets (Research Features)

**`client.v3.image_sets`**

#### generate_seed()
Generate random seed for image randomization.

```python
client.v3.image_sets.generate_seed(image_set_id: int) -> dict
```

Returns: `{"seed": int}`

#### get_seed()
Get user's current seed.

```python
client.v3.image_sets.get_seed(image_set_id: int) -> dict
```

Returns: `{"seed": int | None}`

#### delete_seed()
Delete user's seed.

```python
client.v3.image_sets.delete_seed(image_set_id: int) -> None
```

#### get_blinds()
Get blind configuration.

```python
client.v3.image_sets.get_blinds(image_set_id: int) -> dict
```

#### update_blinds()
Update blind settings (PATCH).

```python
client.v3.image_sets.update_blinds(image_set_id: int, data: dict) -> dict
```

#### delete_blinds()
Delete blind configuration.

```python
client.v3.image_sets.delete_blinds(image_set_id: int) -> None
```

---

### Other V3 Resources

**AnnotationClasses** - `client.v3.annotation_classes`
- `list()` - List annotation classes
- `get(id)` - Get annotation class
- `create(data)` - Create annotation class
- `update(id, data)` - Update annotation class
- `delete(id)` - Delete annotation class

**ChannelGroups** - `client.v3.channel_groups`
- `list()` - List channel groups
- `get(id)` - Get channel group
- `create(data)` - Create channel group
- `update(id, data)` - Update channel group
- `delete(id)` - Delete channel group
- `add_to_repo(channel_group_id, repo_id)` - Add to repository
- `remove_from_repo(channel_group_id, repo_id)` - Remove from repository

**AppConfig** - `client.v3.app_config`
- `list()` - List app configs
- `get(id)` - Get config by ID (string ID)
- `update(id, data)` - Update config value

**AuditLogs** - `client.v3.audit_logs`
- `get_status()` - Get audit log processing status

**Users** - `client.v3.users`
- `get_settings(user_id)` - Get user settings
- `update_settings(user_id, data)` - Update user settings (PATCH)

**Images** - `client.v3.images`
- `get(id)` - Get image metadata

---

## Filter Models

### ImageSetFilters

```python
from concentriq.models.filters import ImageSetFilters

filters = ImageSetFilters(
    ownerId: int = None,
    isFavorite: bool = None,
    archived: bool = None,
    workflowId: int = None,
    generalSearch: str = None,
    # ... 21+ fields total
)
```

### ImageFilters

```python
from concentriq.models.filters import ImageFilters

filters = ImageFilters(
    imageSetId: int = None,
    hasAnnotations: bool = None,
    isFluorescence: bool = None,
    # ... 25+ fields total
)
```

### FolderFilters

```python
from concentriq.models.filters import FolderFilters

filters = FolderFilters(
    imageSetId: int = None,
    folderId: int = None,
    hasMetadata: bool = None,
    hasAttachments: bool = None,
    name: str = None
)
```

### AnnotationFilters

```python
from concentriq.models.filters import AnnotationFilters

filters = AnnotationFilters(
    annotationId: int = None,
    imageId: int = None,
    text: str = None,
    annotationClassId: int = None
)
```

### MetadataValueFilters

```python
from concentriq.models.filters import MetadataValueFilters

filters = MetadataValueFilters(
    imageSetId: int = None,
    imageId: int = None,
    folderId: int = None,
    annotationId: int = None,
    # ... 9 fields total
)
```

---

## Exceptions

All exceptions are in `concentriq.exceptions`:

```python
from concentriq.exceptions import (
    APIError,              # Base exception
    AuthenticationError,   # 401 - Invalid credentials
    AuthorizationError,    # 403 - Insufficient permissions
    NotFoundError,         # 404 - Resource not found
    ValidationError,       # 400/422 - Invalid request
    ServerError,           # 5xx - Server error
)
```

---

## Next Steps

- **[Usage Guide](usage.md)** - Practical examples
- **[Installation Guide](installation.md)** - Setup and configuration
