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

# Python API reference

> Reference for the HiddenLayer Python SDK: client constructor, module exports, resource methods with HTTP endpoints and return types, high-level helpers, and exceptions.

This page lists the public classes, methods, and exceptions in the HiddenLayer Python SDK (`hiddenlayer-sdk`) version 3.10.0. It is built from the SDK's [api.md](https://github.com/hiddenlayerai/hiddenlayer-sdk-python/blob/main/api.md) and its source code.

Use it to look up a signature or return type. For explanations and complete examples, see [Core concepts](/docs/integrations/sdk_python/core_concepts) and [API usage examples](/docs/integrations/sdk_python/api_examples). For REST request and response field details, see the [HiddenLayer developer portal](https://dev.hiddenlayer.ai/).

## How to read this page

* Signatures show the synchronous client (`HiddenLayer`). The async client (`AsyncHiddenLayer`) has the same methods. Call them with `await`, and async paginated results support `async for`.
* Arguments after `*` are keyword-only.
* `omit` means "not sent". If you do not pass the argument, the SDK leaves it out of the request.
* Response types are importable from `hiddenlayer.types` (and subpackages such as `hiddenlayer.types.scans`).
* **Beta** endpoints emit `hiddenlayer.BetaWarning` and can change without notice. **Deprecated** methods are marked with `typing_extensions.deprecated` and should not be used in new code.

### Common request options

Every generated resource method also accepts these keyword-only arguments. They are omitted from the signatures below for readability.

| Argument | Type | Purpose |
| - | - | - |
| `extra_headers` | `Mapping[str, str] \| None` | Send additional HTTP headers. |
| `extra_query` | `Mapping[str, object] \| None` | Add query string parameters. |
| `extra_body` | `Mapping[str, object] \| None` | Add JSON body properties. |
| `timeout` | `float \| httpx.Timeout \| None` | Override the client timeout for this request, in seconds. |

Values passed through these options take precedence over values set on the client or by the method. The high-level helpers (`model_scanner`, `community_scanner`, `evaluation_sessions`) do not accept these options.

Every resource also exposes `.with_raw_response` and `.with_streaming_response` prefixes. See [Raw and streaming responses](/docs/integrations/sdk_python/core_concepts#raw-and-streaming-responses).

## Clients

```python theme={null}
from hiddenlayer import HiddenLayer, AsyncHiddenLayer
# Aliases: hiddenlayer.Client, hiddenlayer.AsyncClient
```

### Constructor

```python theme={null}
HiddenLayer(
    *,
    bearer_token: str | None = None,
    client_id: str | None = None,
    client_secret: str | None = None,
    environment: Literal["prod-us", "prod-eu"] = NOT_GIVEN,
    base_url: str | httpx.URL | None = NOT_GIVEN,
    timeout: float | httpx.Timeout | None = NOT_GIVEN,
    max_retries: int = 2,
    default_headers: Mapping[str, str] | None = None,
    default_query: Mapping[str, object] | None = None,
    http_client: httpx.Client | None = None,
)
```

| Parameter | Type | Default | Environment variable | Description |
| - | - | - | - | - |
| `bearer_token` | `str \| None` | `None` | `HIDDENLAYER_TOKEN` | Access token sent as `Authorization: Bearer <token>`. Not refreshed by the SDK. |
| `client_id` | `str \| None` | `None` | `HIDDENLAYER_CLIENT_ID` | Client ID for the OAuth2 client credentials flow. |
| `client_secret` | `str \| None` | `None` | `HIDDENLAYER_CLIENT_SECRET` | Client secret for the OAuth2 client credentials flow. |
| `environment` | `"prod-us" \| "prod-eu"` | `"prod-us"` | None | Region. Selects the base URL from `ENVIRONMENTS`. Raises `ValueError` if `HIDDENLAYER_BASE_URL` is also set, or if the value is unknown. |
| `base_url` | `str \| httpx.URL \| None` | Derived from `environment` | `HIDDENLAYER_BASE_URL` | Full API base URL. Overrides `environment`. |
| `timeout` | `float \| httpx.Timeout \| None` | `httpx.Timeout(60.0, connect=5.0)` | None | Request timeout. |
| `max_retries` | `int` | `2` | None | Automatic retries for retryable failures. `0` disables retries. |
| `default_headers` | `Mapping[str, str] \| None` | `None` | `HIDDENLAYER_CUSTOM_HEADERS` | Headers sent with every request. The environment variable holds newline-separated `Name: value` lines. Explicit `default_headers` win on conflicts. |
| `default_query` | `Mapping[str, object] \| None` | `None` | None | Query parameters sent with every request. |
| `http_client` | `httpx.Client` (sync) or `httpx.AsyncClient` (async) | SDK default | None | Custom HTTP client. Use `DefaultHttpxClient` (sync), or `DefaultAsyncHttpxClient` or `DefaultAioHttpClient` (async), to keep the SDK defaults. |

Base URL resolution order: `base_url` argument, then `environment` argument, then `HIDDENLAYER_BASE_URL`, then `prod-us`. The `HIDDENLAYER_LOG` environment variable (`info` or `debug`) controls logging.

### Client methods and attributes

| Member | Description |
| - | - |
| `with_options(**overrides)` | Returns a new client with overridden settings (`timeout`, `max_retries`, `http_client`, `default_headers`, `default_query`, credentials, `base_url`, `environment`). Alias of `copy()`. |
| `close()` | Closes HTTP connections (`await client.close()` for async). The client also works as a context manager (`with` / `async with`). |
| `get()`, `post()`, `put()`, `patch()`, `delete()` | Send a request to any path. Use `cast_to=httpx.Response` for an untyped response. See [custom requests](/docs/integrations/sdk_python/api_examples#call-an-endpoint-the-sdk-does-not-wrap-advanced). |
| `models`, `evaluations`, `evaluation_sessions`, `prompt_analyzer`, `interactions`, `runtime`, `sensors`, `scans`, `model_scanner`, `community_scanner` | Resource attributes, documented below. |

## Module-level exports

Import these from the top-level `hiddenlayer` package.

| Name | Description |
| - | - |
| `HiddenLayer`, `AsyncHiddenLayer`, `Client`, `AsyncClient` | Client classes. |
| `HiddenLayerError`, `APIError`, `APIStatusError`, `APIConnectionError`, `APITimeoutError`, `APIResponseValidationError`, `BadRequestError`, `AuthenticationError`, `PermissionDeniedError`, `NotFoundError`, `ConflictError`, `UnprocessableEntityError`, `RateLimitError`, `InternalServerError` | Exception classes. See [Exceptions](#exceptions). |
| `DefaultHttpxClient` | `httpx.Client` subclass with the SDK's default settings. Pass it to `http_client=` to customize proxies or transports. |
| `DefaultAsyncHttpxClient` | Async equivalent of `DefaultHttpxClient`. |
| `DefaultAioHttpClient` | `aiohttp`-based HTTP client for `AsyncHiddenLayer`. Requires `pip install "hiddenlayer-sdk[aiohttp]"`. |
| `BetaWarning` | `UserWarning` subclass emitted when you call a Beta endpoint. |
| `ENVIRONMENTS` | `dict` mapping environment names to base URLs: `{"prod-us": "https://api.us.hiddenlayer.ai", "prod-eu": "https://api.eu.hiddenlayer.ai"}`. |
| `DEFAULT_TIMEOUT` | `httpx.Timeout(timeout=60, connect=5.0)` |
| `DEFAULT_MAX_RETRIES` | `2` |
| `__version__` | Installed SDK version string, for example `"3.10.0"`. |
| `file_from_path(path)` | Reads a file and returns a `(file_name, contents)` tuple for file-upload parameters. |
| `ModelScanner`, `AsyncModelScanner`, `CommunityScanner`, `AsyncCommunityScanner` | High-level helper classes. Use them through `client.model_scanner` and `client.community_scanner`. |
| `BaseModel` | Base class of all response models. Provides `to_dict()` and `to_json()`. |
| `APIResponse`, `AsyncAPIResponse` | Types returned by `.with_raw_response` calls. |

## Models

### `client.models.retrieve`

```python theme={null}
client.models.retrieve(model_id: str) -> ModelRetrieveResponse
```

`GET /api/v2/models/{model_id}`. Returns the model's `name`, `source`, `model_id`, `tenant_id`, and `versions`.

### `client.models.delete`

```python theme={null}
client.models.delete(model_id: str) -> None
```

`DELETE /api/v2/models/{model_id}`. Deletes a model. This operation is irreversible.

### `client.models.cards.list`

**Deprecated**

```python theme={null}
client.models.cards.list(
    *,
    aidr_severity: list[Literal["SAFE", "UNSAFE", "SUSPICIOUS"]] = omit,
    aidr_status: Literal["ENABLED", "DISABLED", "ANY"] = omit,
    limit: int = omit,
    model_created: ModelCreated = omit,
    model_name: ModelName = omit,
    modscan_severity: list[str] = omit,
    modscan_status: Literal["ENABLED", "DISABLED", "ANY"] = omit,
    offset: int = omit,
    policy_status: list[Literal["COMPLIANT", "NONCOMPLIANT"]] = omit,
    provider: list[Literal["AZURE", "ADHOC"]] = omit,
    sort: str = omit,
    source: Source = omit,
) -> SyncOffsetPage[CardListResponse]
```

`GET /models/v4/cards`. Lists model cards with offset pagination. Deprecated in favor of `GET /asset-inventory/v2/assets`, which this SDK version does not expose.

## Evaluations: red team

All `client.evaluations.red_team` methods are **Beta**. Most users should use the [`evaluation_sessions.red_team` helper](#evaluation-sessions-red-team) instead. Types are in `hiddenlayer.types.evaluations`.

### `client.evaluations.red_team.create`

**Beta**

```python theme={null}
client.evaluations.red_team.create(
    *,
    name: str,
    attacker_guidance: str = omit,
    attacker_max_generation_attempts: int = omit,
    attacker_model: str = omit,
    config_id: str = omit,
    evaluation_report_model: str = omit,
    execution_strategy_type: Literal["RANDOM", "SINGLE", "STATIC_PROMPT_SET"] = omit,
    hl_project_id: str = omit,
    max_parallel_techniques: int = omit,
    max_turns: int = omit,
    n_random_techniques: int = omit,
    objective_ids: Sequence[str] = omit,
    objective_judge_model: str = omit,
    prompt_set_id: str = omit,
    refusal_judge_model: str = omit,
    sessions_per_technique: int = omit,
    severity_mapping: dict[str, Literal["CRITICAL", "HIGH", "MEDIUM", "LOW", "NONE"]] = omit,
    target_model: str = omit,
    target_system_prompt: str = omit,
) -> RedTeamCreateResponse
```

`POST /evaluations/v1/red-team`. Starts a red team workflow.

### `client.evaluations.red_team.retrieve_evaluation_results`

**Beta**

```python theme={null}
client.evaluations.red_team.retrieve_evaluation_results(workflow_id: str) -> RedTeamRetrieveEvaluationResultsResponse
```

`GET /evaluations/v1/red-team/{workflow_id}`. Returns the workflow's results and report.

### `client.evaluations.red_team.retrieve_next_action`

**Beta**

```python theme={null}
client.evaluations.red_team.retrieve_next_action(workflow_id: str) -> RedTeamRetrieveNextActionResponse
```

`GET /evaluations/v1/red-team/{workflow_id}/next-action`. Returns the next action, such as an attack prompt to send to your target.

### `client.evaluations.red_team.retrieve_status`

**Beta**

```python theme={null}
client.evaluations.red_team.retrieve_status(workflow_id: str) -> RedTeamRetrieveStatusResponse
```

`GET /evaluations/v1/red-team/{workflow_id}/status`. Returns the workflow status and progress.

### `client.evaluations.red_team.submit_target_response`

**Beta**

```python theme={null}
client.evaluations.red_team.submit_target_response(
    workflow_id: str,
    *,
    session_id: str,
    target_response: str,
) -> RedTeamSubmitTargetResponseResponse
```

`POST /evaluations/v1/red-team/{workflow_id}/target-response`. Submits your target model's reply to an attack prompt.

### `client.evaluations.red_team.terminate`

**Beta**

```python theme={null}
client.evaluations.red_team.terminate(workflow_id: str) -> None
```

`POST /evaluations/v1/jobs/{workflow_id}/termination`. Stops a running workflow. This cannot be undone.

## Evaluation sessions: red team

**Beta** (wraps the Beta `evaluations.red_team` endpoints)

High-level session management, accessed through `client.evaluation_sessions.red_team`. The classes are importable as `from hiddenlayer.lib import EvaluationSessionsResource, AsyncEvaluationSessionsResource`. See [Attack simulation](/docs/integrations/sdk_python/attack_simulation) for a walkthrough.

### `start_session`

```python theme={null}
client.evaluation_sessions.red_team.start_session(
    *,
    name: str,
    target_model: str,
    target_system_prompt: str = "",
    objective_ids: list[str] = omit,
    refusal_judge_model: str = omit,
    objective_judge_model: str = omit,
    attacker_model: str = omit,
    evaluation_report_model: str = omit,
    attacker_guidance: str = omit,
    severity_mapping: dict[str, Literal["CRITICAL", "HIGH", "MEDIUM", "LOW", "NONE"]] = omit,
    config_id: str = omit,
    max_turns: int = 3,
    execution_strategy_type: str = "random",
    attacker_max_generation_attempts: int = 2,
    n_random_techniques: int = 1,
    max_parallel_techniques: int = 1,
    prompt_set_id: str = omit,
    hiddenlayer_project_id: str | None = None,
    poll_interval: float = 2.0,
    poll_max_wait: float | None = None,
    sessions_per_technique: int | None = 1,
) -> RedTeamSession  # AsyncRedTeamSession on the async client
```

Starts a red team workflow and returns a session object. `execution_strategy_type` must be `"single"`, `"random"`, or `"static_prompt_set"`. Any other value raises `ValueError`. `"static_prompt_set"` requires `prompt_set_id`.

### `resume_session`

```python theme={null}
client.evaluation_sessions.red_team.resume_session(
    workflow_id: str,
    *,
    poll_interval: float = 2.0,
    poll_max_wait: float | None = None,
    max_parallel_techniques: int | None = None,
) -> RedTeamSession  # AsyncRedTeamSession on the async client
```

Reconnects to an existing workflow by ID.

### `terminate_session`

```python theme={null}
client.evaluation_sessions.red_team.terminate_session(workflow_id: str) -> None
```

Stops a running workflow. This cannot be undone.

### Session objects

`RedTeamSession` (sync) and `AsyncRedTeamSession` (async) are returned by `start_session()` and `resume_session()`.

| Member | Signature | Description |
| - | - | - |
| `workflow_id` | property, `str` | The workflow ID. Save it to resume or terminate later. |
| `name` | property, `str` | The session name. |
| `get_next_action` | `get_next_action(*, block: bool = True) -> RedTeamRetrieveNextActionResponse` | Polls for the next action. With `block=True`, waits until one is ready. |
| `wait_for_completion` | `wait_for_completion(poll_interval: float = 3.0, max_wait: float \| None = 300.0, verbose: bool = False) -> None` | Polls until a terminal status: `COMPLETED`, `FAILED`, `CANCELLED`, `TERMINATED`, or `TIMED_OUT`. Raises `PollTimeoutError` after `max_wait` seconds. |
| `iterate_actions` | `iterate_actions() -> Iterator[RedTeamRetrieveNextActionResponse]` | Yields attack actions until the workflow completes. Use `async for` on the async session. |
| `run_with_callback` | `run_with_callback(handler) -> None` | Drives the session sequentially. `handler(attack_prompt, history, session_id, target_system_prompt)` returns your target's reply as a `str` (a coroutine on the async session). Waits for completion before returning. |
| `get_available_actions` | `get_available_actions(max_actions: int = 10) -> list[RedTeamRetrieveNextActionResponse]` | **Async only.** Non-blocking fetch of up to `max_actions` ready actions. |
| `run_with_callback_parallel` | `run_with_callback_parallel(handler, max_parallel: int \| None = None, poll_batch_interval: float = 0.5) -> None` | **Async only.** Processes actions in parallel. When `max_parallel` is `None`, uses the session's `max_parallel_techniques`. |

## Prompt Analyzer

### `client.prompt_analyzer.create`

```python theme={null}
client.prompt_analyzer.create(
    *,
    prompt: str,
    model: str = omit,
    output: str = omit,
    hl_project_id: str = omit,
    x_requester_id: str = omit,
) -> PromptAnalyzerCreateResponse
```

`POST /api/v1/submit/prompt-analyzer`. Analyzes a prompt and optional model output. The response includes `verdict`, `categories`, `results`, `policy`, `frameworks`, `model`, `provider`, and `elapsed_ms`. `hl_project_id` is sent as the `HL-Project-Id` header.

## Interactions

### `client.interactions.analyze`

```python theme={null}
client.interactions.analyze(
    *,
    metadata: Metadata,
    input: Input = omit,
    output: Output = omit,
    hl_project_id: str = omit,
) -> InteractionAnalyzeResponse
```

`POST /detection/v1/interactions`. Analyzes LLM input and output with AI Runtime Security. `metadata` requires `model` and `requester_id`, and accepts an optional `provider`. `input` and `output` take `{"messages": [{"role": "...", "content": "..."}]}`. The response includes `analysis`, `analyzed_data`, `metadata`, `modified_data`, and an optional `evaluation` (`action`, `has_detections`, `threat_level`). See [Runtime security](/docs/integrations/sdk_python/runtime_security).

## Runtime

All `client.runtime` methods emit `BetaWarning` in version 3.10.0.

### `client.runtime.evaluate_interaction`

**Beta**

```python theme={null}
client.runtime.evaluate_interaction(
    *,
    interaction: Interaction,
    metadata: Metadata,
    hl_project_id: str = omit,
) -> RuntimeEvaluateInteractionResponse
```

`POST /detection/v2/interaction-evaluations`. Evaluates a full agentic interaction. `metadata` requires `model`, `provider`, and `requester_id`, and accepts an optional `external_session_id`. The response includes `outcome` (`action`, `threat_level`, `detections`, `effective_interaction`), `evaluated_interaction`, and `metadata`.

### `client.runtime.evaluate_request`

**Beta**

```python theme={null}
client.runtime.evaluate_request(
    *,
    body: dict[str, object],
    hl_project_id: str = omit,
    hl_runtime_session_id: str = omit,
) -> dict[str, object]
```

`POST /detection/v2/request-evaluations`. Evaluates a provider-native request payload before you send it to the model. Read the `hl-runtime-action` response header with `with_raw_response` to detect a block.

### `client.runtime.evaluate_response`

**Beta**

```python theme={null}
client.runtime.evaluate_response(
    *,
    body: dict[str, object],
    hl_project_id: str = omit,
    hl_runtime_session_id: str = omit,
) -> dict[str, object]
```

`POST /detection/v2/response-evaluations`. Evaluates a provider-native model response before you return it to the user.

## Sensors

**Deprecated.** The SDK docstring states each sensors endpoint "will be removed after April 13, 2026". Do not use these methods in new code.

| Method | HTTP | Returns |
| - | - | - |
| `client.sensors.create(*, plaintext_name: str, active: bool = omit, adhoc: bool = omit, tags: dict[str, object] = omit, version: int = omit)` | `POST /api/v2/sensors/create` | `SensorCreateResponse` |
| `client.sensors.retrieve(sensor_id: str)` | `GET /api/v2/sensors/{sensor_id}` | `SensorRetrieveResponse` |
| `client.sensors.update(sensor_id: str, *, active: bool = omit, plaintext_name: str = omit, tags: dict[str, object] = omit)` | `PUT /api/v2/sensors/{sensor_id}` | `SensorUpdateResponse` |
| `client.sensors.delete(sensor_id: str)` | `DELETE /api/v2/sensors/{sensor_id}` | `None` |
| `client.sensors.query(*, filter: Filter = omit, order_by: str = omit, order_dir: Literal["asc", "desc"] = omit, page_number: int = omit, page_size: int = omit)` | `POST /api/v2/sensors/query` | `SensorQueryResponse` |

## Scans: results

Types are in `hiddenlayer.types.scans`.

### `client.scans.results.list_files`

```python theme={null}
client.scans.results.list_files(
    scan_id: str,
    *,
    cursor: str = omit,
    has_detections: bool = omit,
    page_size: int = omit,
) -> SyncCursorPagination[ScanFileResult]
```

`GET /scan/v3/results/{scan_id}/files`. Returns per-file results with cursor pagination. Iterate the result to fetch all pages automatically, or use `.items`, `.has_next_page()`, `.get_next_page()`, and `.next_page_info()`. `has_detections=True` returns only files with detections.

### `client.scans.results.retrieve_summary`

```python theme={null}
client.scans.results.retrieve_summary(scan_id: str) -> ScanReportSummary
```

`GET /scan/v3/results/{scan_id}/summary`. Returns status, inventory, summary counts, compliance, and intelligence for a scan, without per-file results.

### `client.scans.results.sarif`

```python theme={null}
client.scans.results.sarif(scan_id: str) -> str
```

`GET /scan/v3/results/{scan_id}/sarif`. Returns the scan results as a SARIF JSON string.

## Scans: jobs

### `client.scans.jobs.retrieve`

```python theme={null}
client.scans.jobs.retrieve(scan_id: str, *, has_detections: bool = omit) -> ScanReport
```

`GET /scan/v3/results/{scan_id}`. Returns the full scan report, including `file_results`. `has_detections=True` filters `file_results` to files with detections (and their parents).

### `client.scans.jobs.list`

```python theme={null}
client.scans.jobs.list(
    *,
    compliance_status: list[Literal["COMPLIANT", "NONCOMPLIANT"]] = omit,
    deep_scan: bool = omit,
    detection_category: str = omit,
    end_time: str | datetime = omit,
    latest_per_model_version_only: bool = omit,
    limit: int = omit,
    model_ids: Sequence[str] = omit,
    model_name: ModelName = omit,            # {"contains": "..."} or {"eq": "..."}
    model_version_ids: Sequence[str] = omit,
    offset: int = omit,
    provider: Sequence[str] = omit,
    region: Sequence[str] = omit,
    request_source: list[Literal["Hybrid Upload", "API Upload", "Integration", "UI Upload", "AI Asset Discovery"]] = omit,
    scanner_version: str = omit,
    severity: Literal["critical", "high", "medium", "low", "none", "unknown", "safe"] = omit,
    sort: str = omit,
    source: Source = omit,                   # {"eq": "adhoc"}
    start_time: str | datetime = omit,
    status: Sequence[str] = omit,
) -> JobListResponse
```

`GET /scan/v3/results`. Lists scans. Not auto-paginated: the response has `items`, `limit`, `offset`, and `total`. Page by changing `offset`.

### `client.scans.jobs.request`

```python theme={null}
client.scans.jobs.request(*, access: Access, inventory: Inventory) -> ScanJob
```

`POST /scan/v3/jobs`. Requests a scan of a model at a remote location. `inventory` requires `model_name`, `model_version`, and `requesting_entity`. `client.community_scanner.community_scan()` wraps this method.

## Scans: upload

These methods implement the multipart upload used by `client.model_scanner`. Most users should call the model scanner instead.

### `client.scans.upload.start`

```python theme={null}
client.scans.upload.start(
    *,
    model_name: str,
    model_version: str,
    requesting_entity: str,
    location_alias: str = omit,
    origin: str = omit,
    request_source: Literal["Hybrid Upload", "API Upload", "Integration", "UI Upload", "AI Asset Discovery"] = omit,
) -> UploadStartResponse
```

`POST /scan/v3/upload`. Starts an upload session for a scan.

### `client.scans.upload.complete_all`

```python theme={null}
client.scans.upload.complete_all(scan_id: str) -> UploadCompleteAllResponse
```

`PATCH /scan/v3/upload/{scan_id}`. Marks all files as uploaded so scanning can begin.

### `client.scans.upload.file.add`

```python theme={null}
client.scans.upload.file.add(
    scan_id: str,
    *,
    file_content_length: int,
    file_name: str = omit,
    file_name_base64: str = omit,
) -> FileAddResponse
```

`POST /scan/v3/upload/{scan_id}/file`. Registers a file in the upload session. Types are in `hiddenlayer.types.scans.upload`.

### `client.scans.upload.file.complete`

```python theme={null}
client.scans.upload.file.complete(file_id: str, *, scan_id: str) -> FileCompleteResponse
```

`PATCH /scan/v3/upload/{scan_id}/file/{file_id}`. Marks one file as fully uploaded.

## Model scanner

High-level helper accessed through `client.model_scanner` (`ModelScanner` or `AsyncModelScanner`). Every method returns a `ScanReport` (`from hiddenlayer.types.scans import ScanReport`). See [Model scanning](/docs/integrations/sdk_python/model_scanning).

```python theme={null}
client.model_scanner.scan_file(
    *,
    model_name: str,
    model_path: str | os.PathLike,
    model_version: str = "1",
    wait_for_results: bool = True,
    request_source: str = "API Upload",
    origin: str = "",
) -> ScanReport

client.model_scanner.scan_folder(
    *,
    model_name: str,
    path: str | os.PathLike,
    model_version: str = "1",
    allow_file_patterns: list[str] | None = None,
    ignore_file_patterns: list[str] | None = None,
    wait_for_results: bool = True,
    request_source: str = "API Upload",
    origin: str = "",
) -> ScanReport

client.model_scanner.scan_s3_model(
    *,
    model_name: str,
    bucket: str,
    key: str,
    model_version: str = "1",
    s3_client: object | None = None,
    wait_for_results: bool = True,
    request_source: str = "API Upload",
) -> ScanReport

client.model_scanner.scan_azure_blob_model(
    *,
    model_name: str,
    account_url: str,
    container: str,
    blob: str,
    model_version: str = "1",
    blob_service_client: object | None = None,
    credential: object | None = None,
    wait_for_results: bool = True,
    request_source: str = "API Upload",
) -> ScanReport

client.model_scanner.scan_huggingface_model(
    *,
    repo_id: str,
    model_name: str | None = None,
    revision: str | None = None,
    local_dir: str = "/tmp",
    allow_file_patterns: list[str] | None = None,
    ignore_file_patterns: list[str] | None = None,
    force_download: bool = False,
    hf_token: str | bool | None = None,
    wait_for_results: bool = True,
    request_source: str = "API Upload",
) -> ScanReport

client.model_scanner.scan_result(*, scan_id: str) -> ScanReport
```

| Method | Description | Extra dependency |
| - | - | - |
| `scan_file` | Uploads and scans one local file. | None |
| `scan_folder` | Uploads and scans all files in a folder and its subfolders. Always skips `*.txt`, `*.md`, `*.lock`, `.gitattributes`, and `.git` folders. | None |
| `scan_s3_model` | Downloads an S3 object to `/tmp`, then scans it. | `boto3` |
| `scan_azure_blob_model` | Downloads an Azure blob to `/tmp`, then scans it. | `azure-identity`, `azure-storage-blob` |
| `scan_huggingface_model` | Downloads a Hugging Face repository (to `/tmp/<repo_id>` by default), then scans it as a folder. | `huggingface_hub` |
| `scan_result` | Returns a snapshot of an existing scan. | None |

`request_source` accepts `"Hybrid Upload"`, `"API Upload"`, `"Integration"`, or `"UI Upload"`. With `wait_for_results=True`, the helper polls until the scan status is `done`, `failed`, or `canceled`, with no overall time limit. A failed scan is returned, not raised, so check `report.status`.

## Community scanner

High-level helper accessed through `client.community_scanner` (`CommunityScanner` or `AsyncCommunityScanner`). HiddenLayer fetches the model from the remote location, so nothing is downloaded to your machine.

```python theme={null}
client.community_scanner.community_scan(
    model_name: str,
    model_path: str,
    model_source: str,              # a CommunityScanSource value
    model_version: str = "main",
    wait_for_results: bool = True,
    request_source: str = "API Upload",
    origin: str = "",
) -> ScanReport

client.community_scanner.scan_result(*, scan_id: str) -> ScanReport
```

`community_scan` raises `ValueError("scan_id must have a value")` if the API does not return a scan ID.

### `CommunityScanSource`

```python theme={null}
from hiddenlayer.lib import CommunityScanSource

CommunityScanSource.LOCAL           # "LOCAL"
CommunityScanSource.AWS_PRESIGNED   # "AWS_PRESIGNED"
CommunityScanSource.AWS_IAM_ROLE    # "AWS_IAM_ROLE"
CommunityScanSource.AZURE_BLOB_SAS  # "AZURE_BLOB_SAS"
CommunityScanSource.AZURE_BLOB_AD   # "AZURE_BLOB_AD"
CommunityScanSource.GOOGLE_SIGNED   # "GOOGLE_SIGNED"
CommunityScanSource.GOOGLE_OAUTH    # "GOOGLE_OAUTH"
CommunityScanSource.HUGGING_FACE    # "HUGGING_FACE"
```

For `HUGGING_FACE`, `model_path` is the repository ID, for example `"drhyrum/bert-tiny-torch-vuln"`.

## Exceptions

All exceptions are importable from `hiddenlayer`, for example `from hiddenlayer import NotFoundError`. See [Error handling](/docs/integrations/sdk_python/error_handling) for patterns.

```text theme={null}
HiddenLayerError
└── APIError
    ├── APIConnectionError
    │   └── APITimeoutError
    ├── APIResponseValidationError
    └── APIStatusError
        ├── BadRequestError            (400)
        ├── AuthenticationError        (401)
        ├── PermissionDeniedError      (403)
        ├── NotFoundError              (404)
        ├── ConflictError              (409)
        ├── UnprocessableEntityError   (422)
        ├── RateLimitError             (429)
        └── InternalServerError        (>= 500)
```

| Status code | Exception |
| - | - |
| 400 | `BadRequestError` |
| 401 | `AuthenticationError` |
| 403 | `PermissionDeniedError` |
| 404 | `NotFoundError` |
| 409 | `ConflictError` |
| 422 | `UnprocessableEntityError` |
| 429 | `RateLimitError` |
| >= 500 | `InternalServerError` |
| Other 4xx | `APIStatusError` |
| No response (network failure) | `APIConnectionError` |
| Request timed out | `APITimeoutError` |

`APIStatusError` and its subclasses expose `status_code`, `response` (the `httpx.Response`), `body`, and `message`. For `APIConnectionError`, the underlying `httpx` exception is available as `e.__cause__`.

### Red team exceptions

```python theme={null}
from hiddenlayer.lib.red_team_exceptions import (
    RedTeamSessionError,
    PollTimeoutError,
    WorkflowNotFoundError,
    InvalidSessionError,
)
```

| Exception | Raised when |
| - | - |
| `RedTeamSessionError` | Base class (subclass of `Exception`). Also raised when a workflow ends with status `FAILED`. |
| `PollTimeoutError` | `wait_for_completion()` exceeds `max_wait`. |
| `WorkflowNotFoundError` | Intended for a workflow ID that does not exist (HTTP 404). |
| `InvalidSessionError` | Intended for an invalid session ID during response submission (HTTP 400). |

These exceptions do not inherit from `hiddenlayer.HiddenLayerError`.

> [!NOTE]
>
> The session helpers map 404 and 400 errors by catching `httpx.HTTPStatusError`, but the SDK client raises `hiddenlayer.APIStatusError` subclasses. In practice you may receive `hiddenlayer.NotFoundError` or `hiddenlayer.BadRequestError` instead of `WorkflowNotFoundError` or `InvalidSessionError`. This needs confirmation. Catch both `RedTeamSessionError` and `hiddenlayer.APIStatusError`. Also, when `poll_max_wait` is exceeded, the helper raises a plain `Exception` ("Polling timed out after ..."), not `PollTimeoutError`.

## Differences from api.md

> [!NOTE]
>
> The SDK's `api.md` differs from the source code in a few places. This page follows the source code (version 3.10.0):
>
> * `api.md` lists the `prod-us` base URL as `https://api.hiddenlayer.ai` and the base URL environment variable as `HIDDEN_LAYER_BASE_URL`. The source uses `https://api.us.hiddenlayer.ai` and `HIDDENLAYER_BASE_URL`.
> * `api.md` omits `model_scanner.scan_azure_blob_model` and `model_scanner.scan_huggingface_model`.
> * `api.md` omits `CommunityScanSource.GOOGLE_SIGNED`.
> * The SDK README's error table omits `ConflictError` (409).
> * The 3.9.0 changelog mentions removing the Beta label from runtime v2 endpoints and exposing a v2 AI Asset Inventory API. In 3.10.0, the runtime v2 endpoints still emit `BetaWarning`, and no asset inventory resource exists on the client. Both need confirmation.
