Skip to main content
This page collects short, runnable recipes that use the SDK’s low-level resources. A low-level resource method sends exactly one HTTP request to one REST endpoint. Use these recipes when the high-level helpers (model_scanner, community_scanner, evaluation_sessions) do not cover what you need, for example listing past scans or exporting a report. If you are new to the SDK, read Core concepts first.

Before you run the examples

Every example creates a client with HiddenLayer() and no arguments. The client reads your credentials from environment variables, so no secrets appear in code. Set them before running a script:
See Authentication and configuration for other options, such as using a bearer token. Replace placeholder values such as YOUR_SCAN_ID or YOUR_MODEL_ID with real IDs from your account. You can find scan IDs with the first recipe below, or in the scan_id field of a ScanReport returned by the model scanner.

List recent scans

client.scans.jobs.list() returns scan results that match your filters. Use it to build dashboards, audit recent activity, or find a scan ID. This method is not auto-paginated. It returns a JobListResponse with four fields: items (the current page), limit, offset, and total (the number of matching scans). To read every matching scan, increase offset until you reach total.
Other useful filters:
The API describes status only as a list of “Statuses”. Using the response status values (such as done) as filter values is an assumption that needs confirmation. The format of the sort parameter is not documented in the SDK, so it is not shown here.

Get a full scan report

client.scans.jobs.retrieve(scan_id) returns a ScanReport for one scan, including per-file results in file_results. Pass has_detections=True to include only files with detections (and their parent files), which keeps large reports small.
Read counts from report.summary (for example report.summary.detection_count). The top-level fields detection_count, file_count, files_with_detections_count, severity, and detection_categories are deprecated.

Get a scan summary

client.scans.results.retrieve_summary(scan_id) returns a ScanReportSummary: the scan’s status, inventory, and summary counts, without per-file results. It is a lighter request than a full report, so use it to check progress or show a headline result.

Iterate over file results

A scan of a large model folder can contain many files. client.scans.results.list_files(scan_id) returns the file results one page at a time using cursor pagination: each page includes a pointer (cursor) to the next page.

Automatic pagination

Loop over the returned object and the SDK requests the next page whenever it needs more items.

Manual page control

Use manual control when you want to process one page at a time, for example to stop early or to show progress per page. The current page’s items are in .items.
With AsyncHiddenLayer, use async for for automatic pagination and await page.get_next_page() for manual control.

Export a SARIF report

SARIF (Static Analysis Results Interchange Format) is a standard JSON format for security findings. Tools such as GitHub code scanning can import SARIF files. client.scans.results.sarif(scan_id) returns the SARIF document as a str, so you can write it straight to a file.

Retrieve a model

client.models.retrieve(model_id) returns a ModelRetrieveResponse with the model’s name, source, model_id, tenant_id, and versions. A scan result’s inventory.model_id gives you the model ID.

Delete a model

client.models.delete(model_id) deletes a model and returns None. Your API credentials need appropriate permissions for this operation.
Deleting a model is irreversible. Confirm the model ID before you delete it, and avoid running deletes from unattended scripts without a confirmation step. The example below retrieves the model first and asks for confirmation.
What else is removed along with the model (for example, its versions and scan results) is not documented in the SDK and needs confirmation.

Analyze a prompt with Prompt Analyzer

client.prompt_analyzer.create() sends a prompt (and optionally a model output) to Prompt Analyzer. The response includes a verdict and per-category results.
The SDK types verdict as an optional boolean. Its exact meaning (for example, whether True means a detection) is not described in the SDK and needs confirmation. See the Prompt Analyzer documentation.

Read response headers with with_raw_response

Add .with_raw_response before the method name to get the HTTP response object. Call .parse() to get the same object the normal method returns. This is how you read the hl-runtime-action header from the agentic evaluation endpoints (see Runtime security).

Stream a response body

.with_streaming_response does not read the body until you ask for it. It must be used in a with block so that the connection is always closed. This example streams a SARIF report to disk in chunks instead of holding it in memory.
Other methods on a streaming response include .read(), .text(), .json(), .iter_text(), .iter_lines(), and .parse().

Set per-request options

Timeouts and retries with with_options

client.with_options() returns a copy of the client with some settings changed. The copy shares the original client’s connection pool. Use it to give one slow operation a longer timeout or to disable retries for one call.
Every method also accepts a timeout= argument directly, for example client.scans.jobs.list(limit=10, timeout=10.0).

Extra headers, query parameters, and body fields

Every method accepts extra_headers, extra_query, and extra_body. Use them to send values that the SDK does not model yet, for example a field recently added to the REST API. Values passed this way take precedence over values set on the client or by the method.
The header and query parameter names above are placeholders. Check the HiddenLayer developer portal for real REST fields. extra_body works the same way for methods that send a JSON body, such as interactions.analyze.

Call an endpoint the SDK does not wrap (advanced)

This is an advanced technique. Prefer the typed resource methods whenever they exist. Responses from custom requests are not validated or typed.
client.get(), client.post(), and the other HTTP verb methods send a request to any path relative to the base URL. They use the client’s authentication, retries, and timeouts. Pass cast_to=httpx.Response to get the raw httpx response. Error responses still raise the usual hiddenlayer exceptions.
To send a JSON body, use client.post(path, cast_to=httpx.Response, body={...}).

Run requests concurrently with the async client

When you need to analyze many interactions at once, the async client lets you send requests in parallel instead of one after another. asyncio.gather starts all calls and waits for them to finish. Passing return_exceptions=True keeps one failure from cancelling the others.
Large batches can trigger rate limiting (HTTP 429). The client retries 429 responses automatically, but you can also limit concurrency with an asyncio.Semaphore.

Use the aiohttp backend

By default the async client uses httpx to send requests. You can switch to aiohttp, which the SDK README recommends for improved concurrency performance. Install the extra first:
Then pass DefaultAioHttpClient() as the HTTP client:

Deprecated resources

  • client.models.cards.list() is deprecated in favor of the asset inventory API (GET /asset-inventory/v2/assets). That endpoint is not available in this SDK version. Avoid building new code on models.cards.list().
  • client.sensors is deprecated. The SDK docstring states the endpoint “will be removed after April 13, 2026”. Do not use it in new code.