Type-safe Python SDK for the Endor Labs REST API — resource facades, operational workflows, and optional agent-context bootstrap
Project description
Endor Labs SDK
AURI platform · Platform docs · Quick start
Type-safe, resource-oriented Python client for the Endor Labs REST API. List, get, create, update, and delete resources (projects, findings, scan results, policies, namespaces, and the rest of the registry-backed resource set) with consistent patterns for filtering, pagination, namespace traversal, and IDE-friendly typed facades.
API stability: Core SDK surfaces (endorlabs.Client, resource facades, F() filters) are semver-stable. The endorlabs.workflows package holds operational CLIs and estate analytics helpers that may evolve faster than core facades — pin versions in production automation if you depend on workflow modules directly.
- Python: 3.12+ (CI gates run on 3.13 — see CONTRIBUTORS.md)
- API spec: OpenAPI (Swagger)
Start here
| You want to… | Go to |
|---|---|
| Use the SDK (API scripts, CI) | Installation → Quick start — no init() required |
| Bootstrap an AI agent (API + skills) | Agent bootstrap — discover() then init() for workflows |
| Try the SDK on a real tenant | docs/guides/examples.md · Try it with skills |
| SDK contracts and deep reference | docs/README.md |
| Contribute to this repo | CONTRIBUTORS.md |
Installation
pip install endorlabs
Or with uv:
uv add endorlabs
From the repository (editable):
git clone https://github.com/endorlabs/endorlabs-sdk.git
cd endorlabs-sdk
uv sync
# or: pip install -e .
Verify: uv run python -c "import endorlabs; print(endorlabs.__version__)"
Source repo: endorlabs/endorlabs-sdk — PyPI distribution name is endorlabs (import endorlabs).
Optional extras
| Extra | Install | Enables |
|---|---|---|
analytics |
pip install 'endorlabs[analytics]' |
DataFrame / Parquet export and estate graph metrics — see docs/estate/README.md |
CSV export from workflows.estate.analyze.cardinality.tabular works without extras. In this repo: uv sync --extra analytics. Product docs: Docs MCP (or llms.txt without MCP).
Quick start
SDK-only — examples below do not call endorlabs.init(). For agent bootstrap, see AGENTS.md.
Credentials: Set env vars per Configuration (API key for CI). For local or agent sessions, probe with uv run endor-auth check or use skill endor-auth-setup (shipped after init()).
Entry point: endorlabs.Client(tenant=...). Resources are PascalCase facades (client.Project, client.Finding, …) matching endorctl api … --resource <Kind>.
Basic usage
import os
import endorlabs
client = endorlabs.Client(
tenant=os.getenv("ENDOR_NAMESPACE", "your-tenant.namespace"),
logging_level="ERROR",
)
namespaces = client.Namespace.list(traverse=True)
projects = client.Project.list(traverse=True, max_pages=1)
if projects:
project = client.Project.get(projects[0].uuid)
print(project.meta.name)
List field masks: a non-empty mask= on list() returns list[dict] wire JSON rows, not
full Pydantic models. Omit mask when you need typed resources end-to-end. See
docs/guides/consumer-ux-list-update.md.
Large estate lists: for project-scoped resources at scale, use
endorlabs.tools.list_sharding or the endor-estate
workflow CLI (see docs/contributing/list-query-performance.md).
Requesting a scan and waiting for results
repo_url = "https://github.com/org/example-repo.git"
projects = client.Project.search_by_name(repo_url, traverse=True, max_pages=2)
project = projects[0] if projects else None
client.Project.update(project, scan_state="SCAN_STATE_REQUEST_FULL_RESCAN")
client.wait_until(
lambda: (
(p := client.Project.get(project))
and p.processing_status.scan_state == "SCAN_STATE_IDLE"
),
timeout=300,
)
scans = client.ScanResult.list_by_project(project, limit=1)
latest_scan = scans[0] if scans else None
findings = client.Finding.list_for_context(latest_scan, max_pages=1) if latest_scan else None
Relationship accessors: list_by_project / list_for_context return list[T] like .list(). Stitch accessors (to_dependency_metadata, …) return RouteResult — use .value / .single and inspect .edge_used / .warnings. Prefer list accessors over hand-built filters when the edge exists in the contract. Catalog: docs/generated-reference/resource-routes.md · guide: docs/guides/facade-helpers.md.
Pagination on .list(): limit=N is an alias for page_size=N (same idea as list_by_project(..., limit=N)). Use max_pages to cap fetch depth.
More patterns (filters, F(), masks, namespace scoping): docs/guides/consumer-ux-list-update.md, docs/guides/retrieving-scan-results.md.
Transport-only APIClient
from endorlabs import APIClient
client = APIClient()
response = client.get("v1/namespaces/tenant.namespace/projects")
Prefer endorlabs.Client for typed models and namespace handling.
Configuration
The SDK uses environment variables only (no config file loading). Precedence: constructor arguments → environment variables → built-in defaults.
| Variable | Purpose |
|---|---|
ENDOR_API |
API base URL (default: https://api.endorlabs.com) |
ENDOR_API_CREDENTIALS_KEY |
API key |
ENDOR_API_CREDENTIALS_SECRET |
API secret |
ENDOR_TOKEN |
Bearer token (read at process start; Client never writes it) |
ENDOR_NAMESPACE |
Default tenant namespace; API scope (SSO tenant root when method is sso) |
ENDOR_LOG_LEVEL |
Optional: DEBUG, INFO, WARNING, ERROR, CRITICAL |
ENDOR_MAX_RETRIES |
Optional: retry count (default: 5) |
ENDOR_REQUEST_TIMEOUT |
Optional: HTTP read timeout in seconds (default: 60) |
ENDOR_API_TIMEOUT |
Optional: endorctl-compatible timeout when request timeout unset |
ENDOR_CREATE_TIMEOUT |
Optional: override timeout for create() POST requests |
Canonical naming is tenant.namespace.child; do not use UUIDs in namespace paths. Full semantics: docs/contracts.md.
Example .env for local runs — use one credential mode (not both):
# Option A — bearer token (common for agent sessions)
ENDOR_TOKEN=your-bearer-token
ENDOR_NAMESPACE=your-tenant.namespace
ENDOR_LOG_LEVEL=INFO
# Option B — API key (CI)
ENDOR_API_CREDENTIALS_KEY=your-api-key
ENDOR_API_CREDENTIALS_SECRET=your-api-secret
ENDOR_NAMESPACE=your-tenant.namespace
ENDOR_LOG_LEVEL=INFO
If both token and API key variables are set, the SDK prefers the token; MCP and endorctl typically fail with conflicting auth.
Bearer sessions are in-memory only: load ENDOR_TOKEN once (or token= on Client), get a one-time stderr warning within 30 minutes of expiry, then fail closed on expiry/401 with an endor-auth refresh hint. Cross-session: uv run endor-auth refresh only — Client never writes secrets to disk or os.environ. Contract: agent-knowledge/contracts/errors-and-auth.md.
Agent bootstrap: discover() vs init()
| Need | Approach |
|---|---|
| INDEX, contracts, traps, stub path — no cwd writes | print(endorlabs.discover()) or python -m endorlabs.examples.agent_bootstrap --dry-run — then read every bootstrap_paths entry |
| Skill playbooks on disk (call graph, scan RCA, bundles) | endorlabs.init() → .endorlabs-context/sdk/skills/<id>/SKILL.md |
| Platform OpenAPI | init(include_openapi=True) (auth required). Product docs: Docs MCP (or llms.txt) |
Runnable probe (paths only): python -m endorlabs.examples.agent_bootstrap --dry-run. Shipped consumer guide: discover().agents_guide.
Call graphs (agents): CallGraphData.fetch() returns the raw envelope only. For search and path queries, read skill endor-fetch-and-search-call-graph after init() (or from the wheel: skills/endor-fetch-and-search-call-graph/SKILL.md via agent_knowledge_manifest()). Prefer endorlabs.workflows.callgraph.resolve_package_version_with_callgraph() and CallGraphData.decode() — spec.call_graph_available does not guarantee stored graph data. Pass namespace=project.tenant_meta.namespace on PV lists and decode.
AI agents
Before Client(), run print(endorlabs.discover()) (or agent_bootstrap --dry-run) and read every path in bootstrap_paths. Before workflow tasks (call graph, project bundle, scan RCA), run endorlabs.init() and open the relevant skill under .endorlabs-context/sdk/skills/.
Browser auth, SSO setup, and skill walkthroughs: docs/guides/examples.md. Credential probe and refresh: uv run endor-auth check / endor-auth refresh (skill endor-auth-setup).
Try it with skills
Guided tenant sessions use shipped agent skills — start with docs/guides/examples.md. Wheel entry: print(endorlabs.discover()) or agent_bootstrap --dry-run; materialize with init() to .endorlabs-context/sdk/.
Further reading
- SDK docs: docs/README.md — contracts, guides, generated reference, errors
- API surfaces: docs/reference/api-surfaces.md
- Architecture (contributors): docs/contributing/architecture.md
- Agents:
discover().agents_guide(shipped wheel) or repo AGENTS.md for contributors - Contribute: CONTRIBUTORS.md · devtools/README.md
License
MIT. See LICENSE.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file endorlabs-0.6.0.tar.gz.
File metadata
- Download URL: endorlabs-0.6.0.tar.gz
- Upload date:
- Size: 730.3 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
383214127fe55be1bc2dbac203343723341b94bf9ab4b118f0bb8218913eb676
|
|
| MD5 |
3c428a55d8a1b24117b4015a9f9ab356
|
|
| BLAKE2b-256 |
5532f67c346dd6d427f573b5a04353a7fe337a2f4679cb5c5a2f0f79d9f69158
|
Provenance
The following attestation bundles were made for endorlabs-0.6.0.tar.gz:
Publisher:
release-tag-publish.yml on endorlabs/endorlabs-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
endorlabs-0.6.0.tar.gz -
Subject digest:
383214127fe55be1bc2dbac203343723341b94bf9ab4b118f0bb8218913eb676 - Sigstore transparency entry: 2139842585
- Sigstore integration time:
-
Permalink:
endorlabs/endorlabs-sdk@907451eb734fdc7b7b1e65fe68e746989e104202 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/endorlabs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-tag-publish.yml@907451eb734fdc7b7b1e65fe68e746989e104202 -
Trigger Event:
workflow_dispatch
-
Statement type:
File details
Details for the file endorlabs-0.6.0-py3-none-any.whl.
File metadata
- Download URL: endorlabs-0.6.0-py3-none-any.whl
- Upload date:
- Size: 1.1 MB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.13
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
0fd3e5c69e1c9f554fc51a2745a94f15cdb24fd6a80e83f30159d476b7d47101
|
|
| MD5 |
65508ab873d28d3b505290220c03c701
|
|
| BLAKE2b-256 |
c44372cb391ebf948654720384cd027f759c6bb8a36e2b4d53d7def905122758
|
Provenance
The following attestation bundles were made for endorlabs-0.6.0-py3-none-any.whl:
Publisher:
release-tag-publish.yml on endorlabs/endorlabs-sdk
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
endorlabs-0.6.0-py3-none-any.whl -
Subject digest:
0fd3e5c69e1c9f554fc51a2745a94f15cdb24fd6a80e83f30159d476b7d47101 - Sigstore transparency entry: 2139842595
- Sigstore integration time:
-
Permalink:
endorlabs/endorlabs-sdk@907451eb734fdc7b7b1e65fe68e746989e104202 -
Branch / Tag:
refs/heads/main - Owner: https://github.com/endorlabs
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
release-tag-publish.yml@907451eb734fdc7b7b1e65fe68e746989e104202 -
Trigger Event:
workflow_dispatch
-
Statement type: