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

# Client

> Complete API reference for the atomscale Client class

The `Client` class is your entry point to the Atomscale API. It provides methods for searching the catalogue, fetching analysis results, uploading files, and downloading processed videos.

<Info>
  [View source on
  GitHub](https://github.com/atomscale-ai/sdk/blob/main/src/atomscale/client.py)
</Info>

## Constructor

```python theme={null}
from atomscale import Client

client = Client(
    api_key="YOUR_API_KEY",
    endpoint="https://api.atomscale.ai/",
    mute_bars=False,
)
```

<ParamField path="api_key" type="str | None" default="None">
  API key for authentication. If not provided, reads from the `AS_API_KEY` environment variable.
</ParamField>

<ParamField path="endpoint" type="str" default="https://api.atomscale.ai/">
  Root API endpoint. Can be overridden with the `AS_API_ENDPOINT` environment variable.
</ParamField>

<ParamField path="mute_bars" type="bool" default="False">
  Whether to suppress progress bars. Set to `True` for non-interactive environments like CI
  pipelines.
</ParamField>

***

## search()

Search and filter items in the data catalogue.

```python theme={null}
results = client.search(
    keywords="GaN",
    include_organization_data=True,
    data_type="rheed_stationary",
    status="success",
)
```

### Parameters

<ParamField path="keywords" type="str | list[str] | None" default="None">
  Keyword or list of keywords to search all catalogue fields. Applied after other explicit filters.
</ParamField>

<ParamField path="include_organization_data" type="bool" default="True">
  Whether to include catalogue entries from other users in your organization.
</ParamField>

<ParamField path="data_ids" type="str | list[str] | None" default="None">
  Filter to specific data IDs.
</ParamField>

<ParamField path="physical_sample_ids" type="str | list[str] | None" default="None">
  Filter by physical sample IDs.
</ParamField>

<ParamField path="project_ids" type="str | list[str] | None" default="None">
  Filter by project IDs.
</ParamField>

<ParamField path="data_type" type="str" default="all">
  Filter by data type.

  | Value               | Description                 |
  | ------------------- | --------------------------- |
  | `rheed_image`       | Single RHEED image          |
  | `rheed_stationary`  | Stationary RHEED video      |
  | `rheed_rotating`    | Rotating RHEED video        |
  | `xps`               | XPS spectrum                |
  | `photoluminescence` | Photoluminescence spectrum  |
  | `pl`                | Alias for photoluminescence |
  | `raman`             | Raman spectrum              |
  | `all`               | All types                   |
</ParamField>

<ParamField path="status" type="str" default="all">
  Filter by pipeline status.

  | Value                | Description            |
  | -------------------- | ---------------------- |
  | `success`            | Analysis completed     |
  | `pending`            | Queued for processing  |
  | `running`            | Currently processing   |
  | `error`              | Analysis failed        |
  | `stream_active`      | Streaming in progress  |
  | `stream_interrupted` | Stream was interrupted |
  | `stream_finalizing`  | Stream finishing       |
  | `stream_error`       | Streaming failed       |
  | `all`                | All statuses           |
</ParamField>

<ParamField path="growth_length" type="tuple[int | None, int | None]" default="(None, None)">
  Filter by growth length in seconds. Tuple of `(min, max)` with `None` for open bounds.
</ParamField>

<ParamField path="upload_datetime" type="tuple[datetime | None, datetime | None]" default="(None, None)">
  Filter by upload timestamp. Tuple of `(min, max)` with `None` for open bounds.
</ParamField>

<ParamField path="last_accessed_datetime" type="tuple[datetime | None, datetime | None]" default="(None, None)">
  Filter by last accessed timestamp. Tuple of `(min, max)` with `None` for open bounds.
</ParamField>

### Returns

<ResponseField name="DataFrame" type="pandas.DataFrame">
  DataFrame with columns:

  | Column                   | Description                                       |
  | ------------------------ | ------------------------------------------------- |
  | `Data ID`                | Unique identifier                                 |
  | `Upload Datetime`        | When the file was uploaded                        |
  | `Last Accessed Datetime` | Last access time                                  |
  | `Type`                   | Data type (rheed\_image, rheed\_stationary, etc.) |
  | `File Name`              | Original filename                                 |
  | `Status`                 | Pipeline status                                   |
  | `File Type`              | File extension/format                             |
  | `Instrument Source`      | Source instrument                                 |
  | `Sample Name`            | Associated sample name                            |
  | `Growth Length`          | Duration in seconds (for videos)                  |
  | `Physical Sample ID`     | Linked physical sample                            |
  | `Physical Sample Name`   | Physical sample name                              |
  | `Sample Notes`           | Associated notes                                  |
  | `Owner`                  | Uploader's name                                   |
  | `Workspaces`             | Associated workspaces                             |
</ResponseField>

### Example

```python theme={null}
from datetime import datetime

results = client.search(
    keywords="GaN",
    data_type="rheed_stationary",
    status="success",
    upload_datetime=(datetime(2025, 1, 1), None),
    growth_length=(3000, None),
)
print(results[["Data ID", "Status", "Sample Name"]])
```

***

## get()

Fetch analysis results for one or more data IDs.

```python theme={null}
analysed = client.get(data_ids=["44fa63b0-74da-4d25-a362-2276c80a670a"])
```

### Parameters

<ParamField path="data_ids" type="str | list[str]" required>
  Data ID or list of data IDs from the catalogue.
</ParamField>

### Returns

<ResponseField name="results" type="list[RHEEDVideoResult | RHEEDImageResult | XPSResult | PhotoluminescenceResult | RamanResult | MetrologyResult | OpticalResult | UnknownResult]">
  List of result objects. The type depends on the source data:

  **RHEEDVideoResult** (for rheed\_stationary, rheed\_rotating):

  * `timeseries_data` - DataFrame with per-frame metrics
  * `snapshot_image_data` - List of extracted frame snapshots

  **RHEEDImageResult** (for rheed\_image):

  * `processed_image` - Processed image as a PIL Image
  * `mask` - Binary segmentation mask (numpy array)
  * `pattern_graph` - NetworkX graph of the diffraction pattern
  * `get_pattern_dataframe()` - Tidy table of spot positions
  * `get_plot()` - Matplotlib figure (params: `show_mask`, `show_spot_nodes`, `symmetrize`, `alpha`)

  **XPSResult** (for xps):

  * `binding_energies` - Array of binding energy values
  * `intensities` - Array of intensity values
  * `predicted_composition` - Dict mapping element symbols to fractional composition
  * `detected_peaks` - Detected peak positions
  * `get_plot()` - Matplotlib figure

  **PhotoluminescenceResult** (for photoluminescence):

  * `energies` - Energy axis values
  * `intensities` - Intensity values
  * `detected_peaks` - Peak labels and positions
  * `get_plot()` - Matplotlib figure

  **RamanResult** (for raman):

  * `raman_shift` - Raman shift axis values
  * `intensities` - Intensity values
  * `detected_peaks` - Peak labels and positions
  * `get_plot()` - Matplotlib figure

  **MetrologyResult** (for metrology/instrument data):

  * `timeseries_data` - DataFrame with instrument readings (pyrometer, pressure, etc.)

  **OpticalResult** (for optical imaging):

  * `timeseries_data` - DataFrame with per-frame metrics (edge perimeter, circularity, etc.)
  * `snapshot_image_data` - List of extracted frame snapshots

  **UnknownResult** (fallback for unsupported types):

  * `data_type` - Type string
  * `catalogue_entry` - Raw catalogue metadata
</ResponseField>

### Example

```python theme={null}
# Search and get results
search_results = client.search(keywords="demo", status="success")
analysed = client.get(search_results["Data ID"].to_list())

# Access time series data
video = analysed[0]
print(video.timeseries_data.columns)
print(video.timeseries_data.tail())
```

***

## upload()

Upload files for analysis.

```python theme={null}
client.upload(files=[
    "/path/to/rheed.mp4",
    "/path/to/xps.vms",
])
```

### Parameters

<ParamField path="files" type="list[str | BinaryIO]" required>
  List of file paths (strings) or open file handles (BinaryIO objects).
</ParamField>

### Returns

None. Files are uploaded and queued for analysis. Check the web UI or use `search()` to monitor progress.

### Example

```python theme={null}
# Upload by path
client.upload(files=[
    "/data/growths/2025-02-10/RHEED-stationary.mp4",
    "/data/growths/2025-02-10/RHEED-rotating.imm",
])

# Upload from file handles
with open("/data/rheed.mp4", "rb") as f:
    client.upload(files=[f])
```

***

## download\_videos()

Download processed or raw videos to disk.

```python theme={null}
client.download_videos(
    data_ids=["44fa63b0-74da-4d25-a362-2276c80a670a"],
    dest_dir="processed/",
    data_type="processed",
)
```

### Parameters

<ParamField path="data_ids" type="str | list[str]" required>
  One or more data IDs from the catalogue.
</ParamField>

<ParamField path="dest_dir" type="str | Path | None" default="None">
  Directory to write files to. Defaults to current working directory.
</ParamField>

<ParamField path="data_type" type="str" default="processed">
  Whether to download `raw` or `processed` data.
</ParamField>

### Returns

None. Files are saved to the destination directory.

### Example

```python theme={null}
search_results = client.search(data_type="rheed_stationary", status="success")

# Download processed videos
client.download_videos(
    data_ids=search_results["Data ID"].to_list(),
    dest_dir="processed/",
)

# Download raw files
client.download_videos(
    data_ids=search_results["Data ID"].to_list(),
    dest_dir="raw/",
    data_type="raw",
)
```

***

## list\_physical\_samples()

List all physical samples accessible to your account.

```python theme={null}
samples = client.list_physical_samples()
```

### Returns

<ResponseField name="samples" type="pandas.DataFrame">
  DataFrame of physical sample records with columns including Physical Sample ID, Physical Sample Name, Project ID, Project Name, Target Material, and Owner.
</ResponseField>

***

## list\_projects()

List all projects accessible to your account.

```python theme={null}
projects = client.list_projects()
```

### Returns

<ResponseField name="projects" type="pandas.DataFrame">
  DataFrame of project records with columns including Project ID, Project Name, Physical Sample Count, Project Notes, and Owner.
</ResponseField>

***

## get\_physical\_sample()

Get all data associated with a physical sample.

```python theme={null}
result = client.get_physical_sample(
    physical_sample_id="sample-uuid",
    align=True,
)
```

### Parameters

<ParamField path="physical_sample_id" type="str" required>
  The physical sample ID.
</ParamField>

<ParamField path="include_organization_data" type="bool" default="True">
  Whether to include data from other users in your organization.
</ParamField>

<ParamField path="align" type="bool | str" default="False">
  Whether to time-align data from multiple sources. Pass `True` for outer join, or a string like `"inner"` to control the join strategy.
</ParamField>

### Returns

<ResponseField name="result" type="PhysicalSampleResult">
  Result object with attributes:

  * `physical_sample_id` - Sample identifier
  * `physical_sample_name` - Sample name
  * `data_results` - List of all result objects for this sample
  * `aligned_timeseries` - Aligned DataFrame if `align` was set, otherwise `None`
</ResponseField>

***

## get\_project()

Get all data associated with a project.

```python theme={null}
result = client.get_project(
    project_id="project-uuid",
    align=True,
)
```

### Parameters

<ParamField path="project_id" type="str" required>
  The project ID.
</ParamField>

<ParamField path="include_organization_data" type="bool" default="True">
  Whether to include data from other users in your organization.
</ParamField>

<ParamField path="align" type="bool | str" default="False">
  Whether to time-align data from multiple sources. Pass `True` for outer join, or a string like `"inner"` to control the join strategy.
</ParamField>

### Returns

<ResponseField name="result" type="ProjectResult">
  Result object with attributes:

  * `project_id` - Project identifier
  * `project_name` - Project name
  * `samples` - List of `PhysicalSampleResult` objects for each sample in the project
  * `aligned_timeseries` - Project-level aligned DataFrame if `align` was set, otherwise `None`
</ResponseField>

***

## list\_growth\_instruments()

List all growth instruments accessible to your account.

```python theme={null}
instruments = client.list_growth_instruments()
```

### Returns

<ResponseField name="instruments" type="list[dict]">
  List of instrument records. Each dict contains:

  * `synth_source_id` - Unique instrument ID (int)
  * `source_name` - Display name
  * `synth_source_type` - Instrument type (mbe, cvd, etc.)
  * `source_manufacturer` - Manufacturer name
  * `source_model` - Model name
</ResponseField>

***

## create\_growth\_instrument()

Register a new growth instrument.

```python theme={null}
instrument_id = client.create_growth_instrument(
    label="Main MBE",
    name="Veeco GEN10",
    instrument_type="mbe",
    serial_id="SN-12345",
)
```

### Parameters

<ParamField path="label" type="str" required>
  Display name for the instrument (e.g., "Main MBE").
</ParamField>

<ParamField path="name" type="str" required>
  Manufacturer and model (e.g., "Veeco GEN10").
</ParamField>

<ParamField path="instrument_type" type="str" required>
  Type of growth instrument.

  | Value     | Description               |
  | --------- | ------------------------- |
  | `mbe`     | Molecular beam epitaxy    |
  | `cvd`     | Chemical vapor deposition |
  | `pvd`     | Physical vapor deposition |
  | `sputter` | Sputtering                |
  | `ald`     | Atomic layer deposition   |
  | `pld`     | Pulsed laser deposition   |
</ParamField>

<ParamField path="serial_id" type="str | None" default="None">
  Optional serial number or identifier.
</ParamField>

### Returns

<ResponseField name="synth_source_id" type="int">
  The ID of the newly created instrument.
</ResponseField>

***

## delete\_growth\_instrument()

Delete a growth instrument.

```python theme={null}
client.delete_growth_instrument(synth_source_id=42)
```

### Parameters

<ParamField path="synth_source_id" type="int" required>
  ID of the instrument to delete.
</ParamField>

### Returns

None.
