Client Types
The Saner Python SDK ships three client classes: SanerClient, PlatformClient, and CvemClient. All three share the exact same underlying configuration: authentication, environment variable fallbacks, retry policy, and logging behave identically regardless of which one you use. The choice between them is not a difference in behavior; it's a difference in which resources are exposed, how they're exposed (nested under two product namespaces vs. flat), and a small but real difference in how many pooled HTTP connections get opened. This guide covers all three, the resource split behind them, and how to pick the right one for your integration.
The Three Client Classes
SanerClient
SanerClient is the universal client. It nests every resource under two namespaces, .platform and .cvem, matching Saner's two product areas.
from saner import SanerClient
client = SanerClient(
api_key="YOUR_API_KEY",
accountid="YOUR_ACCOUNT_ID",
)
organizations = client.platform.Organization.get()
job_status = client.cvem.Patch.getRemediationJobStatus(accountid="Default", name="job1")Use SanerClient when a single script or service needs both platform resources (organizations, users, accounts) and CVEM resources (vulnerability, patch, compliance), or when you're not yet sure which resources you'll need and want the option to reach either without changing your import.
PlatformClient
PlatformClient exposes only the 7 platform resources, flat on the client, with no .platform prefix needed.
from saner.platform import PlatformClient
client = PlatformClient(
api_key="YOUR_API_KEY",
accountid="YOUR_ACCOUNT_ID",
)
organizations = client.Organization.get()Use PlatformClient when your integration only ever manages organizations, users, accounts, groups, service provisioning, reports, or MFA policy, and never calls a CVEM resource.
CvemClient
CvemClient exposes only the 13 CVEM resources, also flat.
from saner.cvem import CvemClient
client = CvemClient(
api_key="YOUR_API_KEY",
accountid="YOUR_ACCOUNT_ID",
)
job_status = client.Patch.getRemediationJobStatus(accountid="Default", name="job1")Use CvemClient when your integration is scoped to vulnerability management, patching, compliance, endpoint, agent, or network-scanner operations and never touches organization/user administration.
Resource-to-Product Mapping
| Product | Resources |
|---|---|
| platform (7) | Organization, Account, User, Group, ServiceProvision, Report, MFA |
| cvem (13) | Agent, Device, CyberHygiene, PostureAnomaly, AssetExposure, Vulnerability, Compliance, RiskPrioritization, Patch, Endpoint, AD, NetworkScanner, Configuration |
On SanerClient, every resource above is reached through its product namespace: client.platform.Organization, client.cvem.Patch. On PlatformClient/CvemClient, drop the namespace: client.Organization, client.Patch.
Note: The name you call a
cvemresource by is sometimes shorter than the class backing it:client.Vulnerabilityis aVulnerabilityManagementinstance,client.ComplianceisComplianceManagement,client.PatchisPatchManagement, andclient.EndpointisEndpointManagement. This only matters if you're inspectingtype(client.Patch)directly or writing type hints against the class name; normal usage (client.Patch.getRemediationJobStatus(...)) is unaffected.
Decision Guide: Which Client Should You Use?
Use SanerClient when
- your integration touches both products (for example, onboarding a new organization and checking its vulnerability posture in the same workflow)
- you're building a general-purpose tool or internal library that shouldn't assume which product its caller needs
- you're following the Quick Start guide and haven't yet settled on a narrower scope
Use PlatformClient when
- your integration is scoped to organization/account/user administration and never calls a CVEM resource
- you want the shortest possible call sites (
client.Organization.get()instead ofclient.platform.Organization.get()) - you're writing a small, single-purpose script or microservice dedicated to platform administration
Use CvemClient when
- your integration is scoped to vulnerability management, patching, compliance, endpoints, or agents, and never calls a platform resource
- the same flat-access and single-purpose reasoning as
PlatformClientapplies, mirrored for the 13 CVEM resources
The Connection-Pooling Cost of Mixing Clients
Every client, regardless of class, opens its own pair of pooled requests.Session objects (one for RPC calls, one for REST calls) the moment it's constructed. SanerClient opens exactly one pair and covers both products through it. If you instead instantiate a PlatformClient and a CvemClient side by side to get the same coverage, you pay for two pairs: twice the open connections, and two independent retry/logging contexts to keep in sync.
| Setup | Session pairs opened | Products covered |
|---|---|---|
One SanerClient | 1 | platform + cvem |
One PlatformClient | 1 | platform only |
One CvemClient | 1 | cvem only |
One PlatformClient + one CvemClient | 2 | platform + cvem |
Note: Prefer a single
SanerClientover instantiating both scoped clients side by side, unless you have a specific reason to isolate their connection pools, for example wanting an independentlog_dirper product (see the Logging guide) or differenttimeout/retry_backoffsettings for platform vs. CVEM calls.
Code Examples
SanerClient: onboarding a new organization, then checking its patch status
from saner import SanerClient
with SanerClient(api_key="YOUR_API_KEY", accountid="YOUR_ACCOUNT_ID") as client:
org = client.platform.Organization.add(
name="Demo Org",
email="[email protected]",
numberofsubscriptions="100",
)
print(org)
job_status = client.cvem.Patch.getRemediationJobStatus(
accountid="Demo Org",
name="job1",
)
print(job_status)PlatformClient: looking up a user
from saner.platform import PlatformClient
with PlatformClient(api_key="YOUR_API_KEY", accountid="YOUR_ACCOUNT_ID") as client:
users = client.User.get(id=["[email protected]"])
print(users)CvemClient: reading an account's cyber hygiene score
from saner.cvem import CvemClient
with CvemClient(api_key="YOUR_API_KEY", accountid="YOUR_ACCOUNT_ID") as client:
score = client.CyberHygiene.getAccountScore(account_name="Demo Account")
print(score)Switching Between Client Types
Because all three classes share the same constructor signature and environment-variable fallbacks (SANER_API_KEY, SANER_ACCOUNT_ID, SANER_BASE_URL, SANER_VERIFY_SSL), switching from one to another is just an import change plus un-nesting or nesting resource access, with no authentication, retry, or logging configuration changes needed.
Before (universal client):
from saner import SanerClient
client = SanerClient(api_key="YOUR_API_KEY", accountid="YOUR_ACCOUNT_ID")
client.platform.Organization.get()After (scoped to platform once you know that's all you need):
from saner.platform import PlatformClient
client = PlatformClient(api_key="YOUR_API_KEY", accountid="YOUR_ACCOUNT_ID")
client.Organization.get()Everything else about the client (configuration, retries, logging, close()) stays exactly the same.
Relationship to Other Guides
- Client Configuration: the constructor parameters described there (
api_key,timeout,retry_backoff,enable_logging, and the rest) apply identically toPlatformClientandCvemClient; this page only covers which resources you get, not how to configure the client. - Multi-Account Usage: that guide covers running multiple instances of one client class (for multiple accounts or regions), which is a different axis from the client type covered here. You can combine both: multiple
CvemClientinstances, one per account, for example. - Logging: the log filename is derived from
accountid/base_url/log_dir, not from the client class; see the note there on exactly what happens to log files when a script uses both aPlatformClientand aCvemClient. - IDE Docstring Support: autocomplete differs by class, nested (
client.platform.,client.cvem.) onSanerClient, flat onPlatformClient/CvemClient.
Updated about 9 hours ago
