SDK Reference (auto-generated)¶
This page is auto-generated from source docstrings via mkdocstrings. For narrative documentation with examples, see the SDK Guide.
Client¶
unitysvc.Client ¶
Client(api_key: str, *, base_url: str | None = None, api_base_url: str | None = None, s3_base_url: str | None = None, smtp_base_url: str | None = None, timeout: float | Timeout | None = 30.0, verify_ssl: bool = True)
Synchronous customer SDK client.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
api_key
|
str
|
A customer API key ( |
required |
base_url
|
str | None
|
Override the default control-plane URL. Falls back to
|
None
|
api_base_url
|
str | None
|
HTTP API gateway base URL. Falls back to
|
None
|
s3_base_url
|
str | None
|
S3 gateway base URL. Falls back to
|
None
|
smtp_base_url
|
str | None
|
SMTP gateway base URL. Falls back to
|
None
|
timeout
|
float | Timeout | None
|
Per-request timeout in seconds. Default 30s. |
30.0
|
verify_ssl
|
bool
|
Whether to verify TLS certificates. Default |
True
|
Attributes¶
Functions¶
from_env
classmethod
¶
Construct a client from environment variables.
Reads :data:ENV_API_KEY (required) and :data:ENV_API_URL
(optional). Any extra keyword arguments are forwarded to the
:class:Client constructor.
resolve ¶
resolve(*, path: str, routing_key: dict | None = None, gateway: str = 'api', strategy: str | None = None) -> ResolveResponse
Dry-run resolve a gateway path + routing key.
Mirrors the gateway's selection decision without executing
the upstream call — useful for debugging routing or
picking a specific service/interface ahead of dispatch.
See :mod:unitysvc.resolve for details.
AsyncClient¶
unitysvc.AsyncClient ¶
AsyncClient(api_key: str, *, base_url: str | None = None, api_base_url: str | None = None, s3_base_url: str | None = None, smtp_base_url: str | None = None, timeout: float | Timeout | None = 30.0, verify_ssl: bool = True)
Asynchronous customer SDK client.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
api_key
|
str
|
A customer API key ( |
required |
base_url
|
str | None
|
Override the control-plane URL. Falls back to
|
None
|
api_base_url, s3_base_url, smtp_base_url
|
Optional gateway
base URLs, matching the sync :class: |
required | |
timeout
|
float | Timeout | None
|
Per-request timeout in seconds. Default 30s. |
30.0
|
verify_ssl
|
bool
|
Whether to verify TLS certificates. Default |
True
|
Attributes¶
Functions¶
from_env
classmethod
¶
Construct an :class:AsyncClient from environment variables.
resolve
async
¶
resolve(*, path: str, routing_key: dict | None = None, gateway: str = 'api', strategy: str | None = None) -> ResolveResponse
Async dry-run resolve. See :func:unitysvc.resolve.resolve.
Resources¶
Groups¶
unitysvc.groups.Groups ¶
Operations on customer-visible service groups (/v1/customer/groups).
Example::
llm = client.groups.get("llm") # by name
page = llm.services() # active-record nav
resp = llm.dispatch(json={"messages": [...]})
The same operations are also available on the manager directly
(client.groups.services("llm")); :class:Group is just a
convenience that pre-binds the slug.
Functions¶
list ¶
List service groups and collections visible to the customer.
Returns platform groups plus the customer's own editable
collections. The visible set is small and bounded — the
endpoint is not paginated and returns a {data, count}
envelope.
owner narrows the server-side result set: "all"
(platform + own, default), "system" (platform only), or
"own" (the customer's own collections only).
name is a client-side substring filter applied on top of
the returned rows (kept for back-compat with scripts that
passed name=). Items are :class:Group wrappers with
bound methods.
create ¶
Create a customer-owned service collection.
Collections are editable, customer-curated catalogs addressable
at /g/<name>. Returns the created group as a :class:Group.
update ¶
update(group_id: str | UUID, *, display_name: Any = _UNSET, description: Any = _UNSET, enabled: Any = _UNSET) -> Group
Update a customer-owned collection's metadata.
Only the fields you pass are changed; omitted fields are left untouched server-side. Returns the updated group.
add_member ¶
add_member(group_id: str | UUID, *, service_id: str | UUID, routing_key: Any = None, sort_order: int = 0) -> ServiceCollectionMemberPublic
Add a member service to a customer-owned collection.
Returns the created member record (raw generated
:class:ServiceCollectionMemberPublic).
members ¶
List the member services of a collection (raw member records).
remove_member ¶
Remove a member service from a customer-owned collection.
services ¶
services(name: str, *, cursor: str | None = None, limit: int = 50, search: str | None = None) -> ServiceListPage
List services that belong to a group.
Cursor-paginated newest-first. Pass the response's
next_cursor back as cursor= to fetch the next page.
This is the canonical service-discovery path — there is no
flat /customer/services list endpoint. Items are
:class:~unitysvc.services.Service wrappers.
dispatch ¶
dispatch(name: str, *, path: str = '', method: str = 'POST', json: Any = None, data: Any = None, headers: dict[str, str] | None = None, timeout: float | None = None) -> httpx.Response
Send an HTTP request through the group's gateway interface.
Resolves group.interface.base_url (the one group-level
interface declared on the group's user_access_interfaces)
and makes a single HTTP request. The gateway's
routing_policy picks a member service via weighted /
content-dependent / price-based selection. No interface=
parameter is needed because groups have at most one
user-facing interface.
For wrapper primitives, use the fluent API on the
active-record :class:Group:
grp.cached(ttl="1h").dispatch(json=body).
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Group slug. |
required |
path
|
str
|
Optional sub-path appended to |
''
|
method
|
str
|
HTTP method. Defaults to |
'POST'
|
json
|
Any
|
Request body as JSON-serializable dict. |
None
|
data
|
Any
|
Raw request body (bytes / str / form). |
None
|
headers
|
dict[str, str] | None
|
Extra headers merged on top of the auth header. |
None
|
timeout
|
float | None
|
Per-request timeout in seconds. |
None
|
Returns:
| Type | Description |
|---|---|
Response
|
The raw |
Response
|
errors (4xx/5xx) are not raised — the caller can inspect |
Response
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If the group has no group-level interface
configured ( |
stream ¶
stream(name: str, *, path: str = '', method: str = 'POST', json: Any = None, data: Any = None, headers: dict[str, str] | None = None, timeout: float | None = None) -> StreamingResponse
Open a streaming HTTP request through the group-level interface.
Same interface-resolution and URL composition as :meth:dispatch,
but returns a context-managed :class:StreamingResponse so the
caller can iterate the body lazily (SSE / NDJSON / chunks) via
iter_events() / iter_bytes() / iter_lines().
Setting the upstream-protocol stream flag in the request
body (e.g. json={"stream": True} for OpenAI-style APIs) is
the caller's job — orthogonal to whether the SDK iterates lazily.
Example::
with client.groups.stream(name, json={..., "stream": True}) as r:
for event in r.iter_events():
if event.kind == "done":
break
handle(event.parsed)
Services¶
unitysvc.services.Services ¶
Operations on customer-visible services (/v1/customer/services).
Example::
svc = client.services.get(service_id)
ifaces = svc.interfaces() # active-record nav
resp = svc.dispatch(json={"messages": [...]})
The same operations are also available on the manager directly
(client.services.dispatch(service_id, …)); :class:Service
is just a convenience that pre-binds the id.
Functions¶
get ¶
Get a single service by UUID (or partial UUID prefix).
Returns 404 for inactive or non-public services — the
customer-visible set matches what
client.groups.services(name) returns.
interfaces ¶
List access interfaces dispatchable by this customer.
Returns shared interfaces plus any enrollment-bound interfaces
owned by the calling customer. Each entry carries an optional
enrollment_id — None for shared, set for BYOK/BYOE.
dispatch ¶
dispatch(service_id: str | UUID, *, interface: str | UUID | None = None, enrollment: str | UUID | None = None, path: str = '', method: str = 'POST', json: Any = None, data: Any = None, headers: dict[str, str] | None = None, timeout: float | None = None) -> httpx.Response
Send an HTTP request to the service through its gateway interface.
Resolves the target interface using :meth:_pick_interface and
POSTs to its base_url using the client's svcpass API key.
Upstream 4xx/5xx responses are returned as-is; the caller is
responsible for inspecting .status_code.
For wrapper primitives (log, cache, failover, tee), use the
fluent API on the active-record :class:Service instead:
svc.cached(ttl="1h").logged().dispatch(json=body). The
fluent API doesn't carry the interface / enrollment selection
logic this method does — use this when you need that
specifically, the fluent API when you don't.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
service_id
|
str | UUID
|
Service UUID. |
required |
interface
|
str | UUID | None
|
Optional interface selector — name or UUID. Required
if the service has more than one interface and no
|
None
|
enrollment
|
str | UUID | None
|
Optional enrollment hint. If set, picks the
interface whose |
None
|
path
|
str
|
Optional sub-path appended to the interface base URL. |
''
|
method
|
str
|
HTTP method. Defaults to |
'POST'
|
json / data
|
Request body (mutually exclusive). |
required | |
headers
|
dict[str, str] | None
|
Extra headers merged on top of the auth header. |
None
|
timeout
|
float | None
|
Per-request timeout in seconds. |
None
|
stream ¶
stream(service_id: str | UUID, *, interface: str | UUID | None = None, enrollment: str | UUID | None = None, path: str = '', method: str = 'POST', json: Any = None, data: Any = None, headers: dict[str, str] | None = None, timeout: float | None = None) -> StreamingResponse
Open a streaming HTTP request through the resolved service interface.
Sibling to :meth:dispatch — same interface resolution, auth,
and URL composition; the difference is that the response body
is consumed lazily via :class:StreamingResponse. Use for
SSE / NDJSON / chunked LLM responses where buffering the full
body before yielding chunks would defeat the streaming UX.
The upstream-protocol stream flag (e.g. json={"stream": True}
for OpenAI-compatible APIs) is orthogonal — set it in the body
if the upstream requires it. stream() controls only how
the SDK consumes the response.
Example::
with client.services.stream(svc_id, json={..., "stream": True}) as r:
print(r.status_code)
for event in r.iter_events():
if event.kind == "done":
break
handle(event.parsed)
Args: same as :meth:dispatch.
Returns:
| Name | Type | Description |
|---|---|---|
A |
StreamingResponse
|
class: |
schedule ¶
schedule(service_id: str | UUID, *, recurrence: dict[str, Any], interface: str | UUID | None = None, enrollment: str | UUID | None = None, path: str = '', method: str = 'POST', json: Any = None, headers: dict[str, str] | None = None, name: str | None = None) -> RecurrentRequestPublic
Schedule a recurring dispatch.
Same interface-resolution rule as :meth:dispatch. Creates a
:class:~unitysvc._generated.models.recurrent_request_public.RecurrentRequestPublic
via POST /customer/recurrent-requests. The server then
fires the request on the given schedule (cron or fixed
interval) against the resolved interface's gateway path.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
service_id
|
str | UUID
|
Service UUID. |
required |
recurrence
|
dict[str, Any]
|
Schedule spec. One of:: {"schedule_type": "interval", "interval_seconds": 300} {"schedule_type": "cron", "cron_expression": "/5 * * * ", "timezone": "UTC"} |
required |
interface / enrollment / path / method / json / headers
|
Same as :meth: |
required | |
name
|
str | None
|
Optional human label for the recurrent request. |
None
|
Enrollments¶
unitysvc.enrollments.Enrollments ¶
Operations on the customer's enrollments (/v1/customer/enrollments).
Example::
enr = client.enrollments.create(
service_id=svc.id,
parameters={"endpoint": "https://my-host", "api_key": "..."},
)
# Poll for activation:
while enr.status == "pending":
time.sleep(1)
enr = enr.refresh()
Or via the :class:~unitysvc.services.Service shortcut:
enr = svc.enroll(parameters={...})
Functions¶
list ¶
List enrollments owned by the calling customer.
get ¶
Get one enrollment by UUID.
create ¶
Enroll in a service (async — poll status via :meth:Enrollment.refresh).
Returns immediately with status="pending"; the server
activates the enrollment in a background worker once required
parameters / secrets are satisfied.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
service_id
|
str | UUID
|
Service UUID. |
required |
parameters
|
dict[str, Any] | None
|
Optional user parameters (BYOK/BYOE values,
model selection, etc.). Secret-shaped keys
( |
None
|
cancel ¶
Cancel (unenroll) — sets status to cancelled.
Access interfaces and parameters are preserved so the customer can re-enroll later with the same parameters to reactivate.
Secrets¶
unitysvc.secrets.Secrets ¶
Operations on the customer's secret store (/v1/customer/secrets).
Functions¶
list ¶
List all secrets owned by the authenticated customer.
get ¶
Get a single secret by name (metadata only — value is never returned).
set ¶
Set name to value (idempotent — creates or replaces).
Maps to PUT /v1/customer/secrets/{name}. Returns the secret's
public metadata; the value itself is never echoed back. The
encryption is handled server-side.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
name
|
str
|
Secret name (must match |
required |
value
|
str
|
Secret value. May be empty. |
required |
Returns:
| Type | Description |
|---|---|
SecretPublic
|
|
Aliases¶
unitysvc.aliases.Aliases ¶
Operations on the customer's service aliases (/v1/customer/aliases).
Functions¶
list ¶
list(*, skip: int = 0, limit: int = 100, name: str | None = None, include_deactivated: bool = False) -> Any
List aliases owned by the authenticated customer.
update ¶
Update an existing alias.
switch_routing ¶
Switch routing on or off for an alias.
When on is True, any sibling alias currently routing the same (name, routing_key) combo is atomically demoted. When False the alias simply stops routing.
RecurrentRequests¶
unitysvc.recurrent_requests.RecurrentRequests ¶
Operations on the customer's recurrent requests
(/v1/customer/recurrent-requests).
Functions¶
list ¶
list(*, service_id: str | UUID | None = None, enrollment_id: str | UUID | None = None, status: RecurrentRequestStatusEnum | str | None = None, skip: int = 0, limit: int = 100) -> RecurrentRequestsPublic
List recurrent requests owned by the authenticated customer.
create ¶
Create a new recurrent request.
update ¶
update(request_id: str | UUID, body: RecurrentRequestUpdate | dict[str, Any]) -> RecurrentRequestPublic
Update an existing recurrent request.
RequestLogs¶
unitysvc.request_logs.RequestLogs ¶
Operations on the customer's request log
(/v1/customer/request-logs).
Functions¶
start ¶
Enable request logging for the authenticated user.
Subsequent gateway dispatches will be persisted and visible via
:meth:list / :meth:get. Idempotent — safe to call when
logging is already on.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
truncate_long_message
|
bool | None
|
Picks the storage mode.
|
None
|
stop ¶
Disable request logging for the authenticated user.
Already-persisted rows remain visible via :meth:list /
:meth:get; only future dispatches are skipped. Idempotent.
list ¶
list(*, skip: int = 0, limit: int = 50, service_id: UUID | None = None, service_enrollment_id: UUID | None = None, status_min: int | None = None, status_max: int | None = None, start_time: datetime | None = None, end_time: datetime | None = None, user_request_path: str | None = None, error_source: str | None = None, error_type: str | None = None, gateway_source: str | None = None) -> RequestLogListResponse
List request logs for the authenticated customer.
Returns lightweight columns (no body / header fields) for fast
pagination. Default time range is the last 24 hours when both
start_time and end_time are omitted.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
skip
|
int
|
Pagination offset. |
0
|
limit
|
int
|
Page size (1–200). |
50
|
service_id
|
UUID | None
|
Filter by service listing. |
None
|
service_enrollment_id
|
UUID | None
|
Filter by enrollment. |
None
|
status_min
|
int | None
|
Min upstream status code (100–599). |
None
|
status_max
|
int | None
|
Max upstream status code (100–599). |
None
|
start_time
|
datetime | None
|
Inclusive lower bound on |
None
|
end_time
|
datetime | None
|
Inclusive upper bound on |
None
|
user_request_path
|
str | None
|
Path-prefix filter. |
None
|
error_source
|
str | None
|
|
None
|
error_type
|
str | None
|
Filter by error type. |
None
|
gateway_source
|
str | None
|
|
None
|
get ¶
Get full detail of a single request log row.
Includes request and response bodies (subject to the backend's redaction rules — upstream identity and credentials are stripped server-side).
Streaming responses¶
Services.stream() / Groups.stream() (and async siblings) return
these context-managed wrappers. See the Streaming
section of the SDK
guide for usage.
Streaming-response primitives for Services.stream / Groups.stream.
Provides lazy iteration over HTTP response bodies — SSE, NDJSON, plain
lines, or raw bytes — selected by Content-Type. Sibling to the
buffered :meth:dispatch path; same auth and interface resolution,
but httpx.Client.stream() instead of request() so the caller
sees chunks as they arrive.
The dominant use case is LLM SSE streaming (data: {...}\n\n
frames terminated by data: [DONE]); the same surface handles
NDJSON and arbitrary binary streams.
Classes¶
StreamEvent
dataclass
¶
One frame from a streaming response body.
Attributes:
| Name | Type | Description |
|---|---|---|
kind |
str
|
|
parsed |
Any
|
JSON-decoded payload for |
raw |
bytes
|
The raw bytes of this frame (the full SSE frame for
|
text |
str | None
|
Decoded UTF-8 text for |
StreamingResponse ¶
Sync context-managed wrapper around an httpx.Response stream.
Created by :meth:Services.stream / :meth:Groups.stream. Opens
the underlying httpx.Client.stream() on __enter__ and
closes it on __exit__. Status/headers are available before
iteration; the body is consumed lazily by iter_events /
iter_bytes / iter_lines.
Attributes¶
response
property
¶
The underlying httpx.Response. Only valid inside the with block.
Functions¶
iter_bytes ¶
Yield raw body chunks as they arrive.
iter_events ¶
Yield :class:StreamEvent objects, discriminated by Content-Type.
text/event-stream→"sse"per frame,"done"ondata: [DONE]. Frames split across TCP chunks are reassembled before yielding.application/x-ndjson/application/jsonl→"ndjson"per line.text/*→"line"per line (text inevent.text).- anything else →
"bytes"per chunk.
AsyncStreamingResponse ¶
Resolve (dry-run primitive)¶
unitysvc.resolve ¶
client.resolve — dry-run gateway route resolution.
Wraps POST /v1/customer/resolve from the generated low-level
client. Answers "what would the gateway do for this path + routing
key?" without executing the upstream call — useful for debugging,
simulating selection, or picking an interface when the caller only
knows gateway semantics.
Functions¶
resolve ¶
resolve(client: AuthenticatedClient, *, path: str, routing_key: dict[str, Any] | None = None, gateway: str = 'api', strategy: str | None = None) -> ResolveResponse
Dry-run resolve a gateway path + routing key to its candidates.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
client
|
AuthenticatedClient
|
Low-level authenticated client (injected by
:class: |
required |
path
|
str
|
Gateway request path (same shape as
|
required |
routing_key
|
dict[str, Any] | None
|
Optional routing key the gateway would match
against interface rules (e.g. |
None
|
gateway
|
str
|
|
'api'
|
strategy
|
str | None
|
Override the group's configured routing strategy
(e.g. |
None
|
Returns:
| Name | Type | Description |
|---|---|---|
A |
ResolveResponse
|
class: |
ResolveResponse
|
with the candidate list, the effective strategy, and an |
|
ResolveResponse
|
optional pre-selected candidate. |
Exceptions¶
unitysvc.exceptions ¶
Exception hierarchy for the customer SDK.
All errors raised by unitysvc are subclasses of
:class:UnitysvcSDKError, which in turn is a subclass of Exception.
This lets callers choose the granularity that fits their use case::
try:
client.secrets.list()
except NotFoundError:
...
except UnitysvcSDKError:
...
Classes¶
UnitysvcSDKError ¶
Bases: Exception
Base class for all errors raised by unitysvc.
APIError ¶
Bases: UnitysvcSDKError
The server returned a non-success status code.
Attributes:
| Name | Type | Description |
|---|---|---|
status_code |
HTTP status code. |
|
detail |
Parsed error payload from the server (usually a dict
matching |
|
response_body |
Raw response bytes, useful for debugging. |
AuthenticationError ¶
PermissionError ¶
NotFoundError ¶
ValidationError ¶
ValidationError(message: str, *, status_code: int, detail: Any = None, response_body: bytes | None = None)
Bases: APIError
400/422. The request body failed server-side validation.
detail typically contains a list of per-field errors.