Python SDK Reference
Package: cpod-sdk
PyPI: pypi.org/project/cpod-sdk
Source: github.com/cpod-ai/cpod-sdk/tree/main/sdks/python
Python: ≥ 3.9
Dependencies: pydantic>=2.0, httpx>=0.26
Clients
The Python SDK provides both synchronous and asynchronous clients with identical APIs.
from cpod import CpodClient, AsyncCpodClient
# Synchronous — for scripts, notebooks, Django sync views
client = CpodClient(
api_key="cpod_live_xxx", # or set CPOD_API_KEY env var
base_url="https://api.cyberpod.app/v1",
timeout=30.0, # seconds
max_retries=3,
)
# Asynchronous — for FastAPI, asyncio apps
async_client = AsyncCpodClient(
api_key="cpod_live_xxx",
timeout=30.0,
max_retries=3,
)The async client is a context manager and should be used with async with to ensure connection pools are properly cleaned up.
PeopleService
Accessed via client.people. Manages people entities — employees, contractors, and service accounts.
from cpod import AsyncCpodClient
from cpod.models import PersonType, PersonStatus
async with AsyncCpodClient() as client:
# List people with optional filters
result = await client.people.list(
status=PersonStatus.ACTIVE,
person_type=PersonType.EMPLOYEE,
limit=50,
)
# result: PaginatedResponse[Person]
# result.data: list[Person]
# result.total: int
# result.next_cursor: str | None
# Get a single person
person = await client.people.get("person_01jm8xk2y3z")
# Create a person
new_person = await client.people.create(
email="alice@acme.com",
first_name="Alice",
last_name="Smith",
person_type=PersonType.EMPLOYEE,
department="Engineering",
tags=["backend", "platform"],
)
# Update
updated = await client.people.update(
"person_01jm8xk2y3z",
department="Platform Engineering",
)
# Deactivate (soft delete — sets status to inactive)
await client.people.deactivate("person_01jm8xk2y3z")
# Auto-paginated iterator
async for person in client.people.list_all(status=PersonStatus.ACTIVE):
print(f"{person.id}: {person.email}")Sync usage
from cpod import CpodClient
with CpodClient() as client:
page = client.people.list(person_type="contractor")
for person in page.data:
print(f"{person.first_name} {person.last_name} — {person.status}")GroupService
Accessed via client.groups. Manages groups and team membership.
from cpod import AsyncCpodClient
async with AsyncCpodClient() as client:
# List groups
result = await client.groups.list(limit=25)
# Get a group
group = await client.groups.get("group_01abc")
# Create a group
new_group = await client.groups.create(
name="Platform Team",
description="Core platform engineering group",
tags=["engineering", "platform"],
)
# Update
await client.groups.update("group_01abc", name="Platform & Infra Team")
# Member management
await client.groups.add_member(
"group_01abc",
person_id="person_01jm8xk2y3z",
role="member", # 'owner' | 'member'
)
await client.groups.remove_member("group_01abc", "person_01jm8xk2y3z")
# Delete
await client.groups.delete("group_01abc")TechnologyService
Accessed via client.technology. Manages technology assets (software, SaaS, infrastructure) and access entitlements.
from cpod import AsyncCpodClient
from cpod.models import AssetType, EntitlementStatus
async with AsyncCpodClient() as client:
# List technology assets
result = await client.technology.list(
asset_type=AssetType.SAAS,
limit=50,
)
# Get a technology asset
asset = await client.technology.get("asset_01xyz")
# Create a technology asset
new_asset = await client.technology.create(
name="GitHub Enterprise",
asset_type=AssetType.SAAS,
vendor="GitHub",
description="Source code management platform",
tags=["devtools", "vcs"],
)
# Update
await client.technology.update("asset_01xyz", description="SCM and CI/CD platform")
# Get entitlements for an asset
entitlements = await client.technology.get_entitlements(
"asset_01xyz",
status=EntitlementStatus.ACTIVE,
)
# Grant an entitlement to a person
await client.technology.grant_entitlement(
asset_id="asset_01xyz",
person_id="person_01jm8xk2y3z",
role="member",
expires_at="2027-01-01T00:00:00Z",
)
# Revoke an entitlement
await client.technology.revoke_entitlement(
asset_id="asset_01xyz",
entitlement_id="ent_01abc",
)LicenseService
Accessed via client.licenses. Manages software licenses and seat assignments.
from cpod import AsyncCpodClient
async with AsyncCpodClient() as client:
# List licenses
result = await client.licenses.list(limit=50)
# Get a license
license = await client.licenses.get("lic_01abc")
# Create a license
new_license = await client.licenses.create(
name="Datadog Pro",
vendor="Datadog",
seat_count=150,
expires_at="2027-06-30T00:00:00Z",
cost_usd=45000.00,
)
# Update
await client.licenses.update("lic_01abc", seat_count=200)
# Get current assignments
assignments = await client.licenses.get_assignments("lic_01abc")
# assignments.data: list[LicenseAssignment]
# assignments.seats_used: int
# assignments.seats_total: int
# Assign a seat to a person
await client.licenses.assign(
license_id="lic_01abc",
person_id="person_01jm8xk2y3z",
)
# Revoke a seat
await client.licenses.revoke(
license_id="lic_01abc",
assignment_id="asgn_01xyz",
)AssetService
Accessed via client.assets. Manages physical assets and cloud resources.
from cpod import AsyncCpodClient
async with AsyncCpodClient() as client:
# List physical assets
physical = await client.assets.list_physical(
location="HQ-NYC",
limit=50,
)
# physical.data: list[PhysicalAsset]
# Get a physical asset
asset = await client.assets.get_physical("asset_01abc")
# Create a physical asset
new_asset = await client.assets.create_physical(
name="MacBook Pro 16\" — Alice Smith",
asset_tag="HWNY-2024-0042",
serial_number="C02ZF1XKMD6T",
location="HQ-NYC",
assigned_to="person_01jm8xk2y3z",
purchased_at="2024-03-15",
tags=["laptop", "apple"],
)
# List cloud resources
cloud = await client.assets.list_cloud(
provider="aws",
region="us-east-1",
limit=100,
)
# cloud.data: list[CloudResource]
# Get a cloud resource
resource = await client.assets.get_cloud("cloud_01xyz")
# Update an asset (works for both PhysicalAsset and CloudResource)
await client.assets.update("asset_01abc", location="HQ-SF")RiskService
Accessed via client.risk. Query vulnerabilities, compliance controls, and risk items across the EDM.
from cpod import AsyncCpodClient
from cpod.models import Severity, VulnerabilityStatus, Framework
async with AsyncCpodClient() as client:
# List vulnerabilities with severity filter
vulns = await client.risk.list_vulnerabilities(
severity=Severity.CRITICAL,
status=VulnerabilityStatus.OPEN,
limit=50,
)
# vulns.data: list[Vulnerability]
# Get a single vulnerability
vuln = await client.risk.get_vulnerability("vuln_01abc")
print(f"CVE: {vuln.cve_id} — {vuln.severity} — {vuln.status}")
print(f"Affected assets: {vuln.affected_asset_ids}")
# Update vulnerability status (e.g. after remediation)
await client.risk.update_vulnerability_status(
"vuln_01abc",
status=VulnerabilityStatus.REMEDIATED,
notes="Patched via Dependabot PR #412",
)
# List compliance controls by framework
controls = await client.risk.list_controls(
framework=Framework.SOC2,
limit=100,
)
# controls.data: list[ComplianceControl]
# Get a single compliance control
control = await client.risk.get_control("ctrl_01xyz")
print(f"{control.framework} / {control.control_id}: {control.title}")
print(f"Status: {control.status} — Owner: {control.owner_id}")
# List risk items
risk_items = await client.risk.list_risk_items(
severity=Severity.HIGH,
limit=50,
)
# risk_items.data: list[RiskItem]
# Get a single risk item
item = await client.risk.get_risk_item("risk_01abc")
print(f"Risk: {item.title} — Score: {item.risk_score}")Key models
from cpod.models import (
Vulnerability, VulnerabilityStatus,
Severity, # critical | high | medium | low
ComplianceControl,
Framework, # soc2 | iso27001 | nist_csf | pci_dss | hipaa | gdpr | cis
RiskItem,
)
class Severity(str, Enum):
CRITICAL = "critical"
HIGH = "high"
MEDIUM = "medium"
LOW = "low"
class Framework(str, Enum):
SOC2 = "soc2"
ISO27001 = "iso27001"
NIST_CSF = "nist_csf"
PCI_DSS = "pci_dss"
HIPAA = "hipaa"
GDPR = "gdpr"
CIS = "cis"RelationshipService
Accessed via client.relationships. Manage typed graph edges between any two EDM entities.
from cpod import AsyncCpodClient
async with AsyncCpodClient() as client:
# List relationships for an entity
rels = await client.relationships.list(
source_id="person_01jm8xk2y3z",
limit=50,
)
# rels.data: list[Relationship]
# Create a relationship
rel = await client.relationships.create(
source_id="person_01jm8xk2y3z",
source_type="person",
target_id="group_01abc",
target_type="group",
relationship_type="member_of",
metadata={"since": "2024-01-15"},
)
# Delete a relationship
await client.relationships.delete("rel_01xyz")
# Fetch the full entity graph (N hops)
graph = await client.relationships.get_graph(
entity_id="person_01jm8xk2y3z",
depth=2,
)
# graph.nodes: list[GraphNode]
# graph.edges: list[Relationship]DataSourceService
Accessed via client.data_sources. Manage data source integrations and trigger syncs.
from cpod import AsyncCpodClient
async with AsyncCpodClient() as client:
# List data sources
sources = await client.data_sources.list(limit=50)
# sources.data: list[DataSource]
# Get a single data source
source = await client.data_sources.get("ds_01abc")
print(f"{source.name} ({source.connector_type}) — {source.status}")
# Create a data source
new_source = await client.data_sources.create(
name="Okta Production",
connector_type="okta",
config={
"domain": "acme.okta.com",
"api_token_secret": "vault:secret/okta/token",
},
sync_schedule="0 */6 * * *", # every 6 hours
)
# Trigger a manual sync
sync_job = await client.data_sources.sync("ds_01abc")
print(f"Sync job started: {sync_job.job_id}")
# Poll sync status
status = await client.data_sources.get_status("ds_01abc")
print(f"Last sync: {status.last_synced_at} — {status.records_synced} records")Pydantic Models
All SDK response objects are Pydantic v2 models. You get:
.model_dump()— serialize to dict.model_dump_json()— serialize to JSON string- Full type annotations and IDE autocomplete
- Runtime validation on deserialization
from cpod.models import (
# People
Person, PersonType, PersonStatus,
# Technology
TechnologyAsset, AssetType, AccessEntitlement, EntitlementStatus,
# Licenses
SoftwareLicense, LicenseAssignment,
# Assets
PhysicalAsset, CloudResource,
# Risk
Vulnerability, Severity, VulnerabilityStatus,
ComplianceControl, Framework, RiskItem,
# Common
Relationship, DataSource, Tag,
ApiResponse, PaginatedResponse,
)
person: Person
print(person.id) # str
print(person.email) # str
print(person.status) # PersonStatus.ACTIVE
print(person.person_type) # PersonType.EMPLOYEE
print(person.created_at) # datetime (UTC-aware)
print(person.model_dump()) # {'id': ..., 'status': 'active', ...}Key enums
class PersonType(str, Enum):
EMPLOYEE = "employee"
CONTRACTOR = "contractor"
SERVICE_ACCOUNT = "service_account"
class PersonStatus(str, Enum):
ACTIVE = "active"
INACTIVE = "inactive"
PENDING = "pending"Error Handling
from cpod.errors import (
CpodError,
NotFoundError,
ValidationError,
AuthError,
RateLimitError,
)
async with AsyncCpodClient() as client:
try:
person = await client.people.get("person_nonexistent")
except NotFoundError as e:
print(f"404: {e.message}")
except ValidationError as e:
for field, msg in e.fields.items():
print(f" {field}: {msg}")
except AuthError as e:
print(f"Auth error ({e.status}): {e.message}")
except RateLimitError as e:
print(f"Rate limited. Retry in {e.retry_after}s")
except CpodError as e:
print(f"API error {e.status} [{e.code}]: {e.message}")