Skip to content

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 | None = None, *, 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 | None

A customer API key (svcpass_...). Omit it (or pass Encodes the customer context, so no separate customer_id is required.

None
base_url str | None

Override the default control-plane URL. Falls back to UNITYSVC_API_URL, then to :data:DEFAULT_API_URL.

None
api_base_url str | None

HTTP API gateway base URL. Falls back to UNITYSVC_API_BASE_URL. Exposed for downstream SDK use.

None
s3_base_url str | None

S3 gateway base URL. Falls back to UNITYSVC_S3_BASE_URL.

None
smtp_base_url str | None

SMTP gateway base URL. Falls back to UNITYSVC_SMTP_BASE_URL.

None
timeout float | Timeout | None

Per-request timeout in seconds. Default 30s.

30.0
verify_ssl bool

Whether to verify TLS certificates. Default True.

True

Attributes

groups property

groups: Groups

services property

services: Services

enrollments property

enrollments: Enrollments

secrets property

secrets: Secrets

aliases property

aliases: Aliases

recurrent_requests property

recurrent_requests: RecurrentRequests

request_logs property

request_logs: RequestLogs

Methods:

from_env classmethod

from_env(**kwargs: object) -> Client

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 | None = None, *, 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 | None

A customer API key (svcpass_...). Omit it (or pass

None
base_url str | None

Override the control-plane URL. Falls back to UNITYSVC_API_URL, then to :data:DEFAULT_API_URL.

None
api_base_url, s3_base_url, smtp_base_url

Optional gateway base URLs, matching the sync :class:Client.

required
timeout float | Timeout | None

Per-request timeout in seconds. Default 30s.

30.0
verify_ssl bool

Whether to verify TLS certificates. Default True.

True

Attributes

groups property

groups: AsyncGroups

services property

services: AsyncServices

enrollments property

enrollments: AsyncEnrollments

secrets property

secrets: AsyncSecrets

aliases property

aliases: AsyncAliases

recurrent_requests property

recurrent_requests: AsyncRecurrentRequests

request_logs property

request_logs: AsyncRequestLogs

Methods:

from_env classmethod

from_env(**kwargs: object) -> AsyncClient

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

Groups(client: LowLevelClient, *, parent: Client)

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.

Methods:

list

list(*, owner: str = 'all', name: str | None = None) -> GroupListPage

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.

get

get(name: str) -> Group

Get a single group by its slug name.

create

create(*, name: str, display_name: str | None = None, description: str | None = None) -> Group

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.

delete

delete(group_id: str | UUID) -> None

Delete a customer-owned collection.

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

members(group_id: str | UUID) -> builtins.list[ServiceCollectionMemberPublic]

List the member services of a collection (raw member records).

remove_member

remove_member(group_id: str | UUID, service_id: str | UUID) -> None

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 interface.base_url (e.g. "completions" for an LLM gateway that already has /v1 in its base).

''
method str

HTTP method. Defaults to POST.

'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 httpx.Response from the gateway. Upstream

Response

errors (4xx/5xx) are not raised — the caller can inspect

Response

.status_code / .json() directly.

Raises:

Type Description
ValueError

If the group has no group-level interface configured (group.interface is None).

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

Services(client: LowLevelClient, *, parent: Client)

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.

Methods:

get

get(service_id: str | UUID) -> Service

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

interfaces(service_id: str | UUID) -> list[AccessInterface]

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_idNone for shared, set for BYOK/BYOE.

access_plan

access_plan(service_id: str | UUID) -> AccessPlan

Return the structured "how to use this service" access plan (#1638).

A generic, context-free plan — the enrollment posture, how to call the service (shared interface or per-enrollment /e/<CODE>), and per-channel pricing and secrets — synthesized from metadata, so no API key is needed. The backend serves structure, not prose; rendering (to text, UI, or LLM markdown) is the caller's job.

documents

documents(service_id: str | UUID, *, category: str | None = None, mime_type: str | None = None, include_content: bool = False, interface: str | None = None) -> ServiceDocumentsResponse

List a service's public documents (code examples, guides, tutorials).

Anonymous-readable. category / mime_type narrow the set (mime_type is the language for code examples — python, bash, …); include_content=True returns each document rendered inline. interface picks which user interface examples render against (by key, e.g. canonical); the response also lists the alternatives in available_interfaces.

document

document(service_id: str | UUID, document_id: str | UUID, *, interface: str | None = None) -> ServiceDocumentsResponse

Fetch one public document, with its content rendered.

Returns the same envelope as :meth:documents with a single entry, so available_interfaces is available alongside it. interface picks the user interface the example renders against.

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 enrollment= hint picks one uniquely.

None
enrollment str | UUID | None

Optional enrollment hint. If set, picks the interface whose enrollment_id matches. Silently ignored when there is exactly one interface.

None
path str

Optional sub-path appended to the interface base URL.

''
method str

HTTP method. Defaults to POST.

'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:StreamingResponse context manager.

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:dispatch — resolve the target interface and compose the gateway URL.

required
name str | None

Optional human label for the recurrent request.

None

Enrollments

unitysvc.enrollments.Enrollments

Enrollments(client: LowLevelClient, *, parent: Client)

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={...})

Methods:

list

list(*, skip: int = 0, limit: int = 100, include_service_details: bool = True, shared: bool = True) -> EnrollmentList

List enrollments visible in the selected scope.

By default this returns shared team enrollments to preserve legacy visibility during the migration. Pass shared=False to list the caller's personal enrollments.

get

get(enrollment_id: str | UUID, *, include_service_details: bool = True) -> Enrollment

Get one enrollment by UUID.

create

create(*, service_id: str | UUID, parameters: dict[str, Any] | None = None, shared: bool = False) -> Enrollment

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. By default, creates a personal enrollment owned by the calling user. Pass shared=True to create a team-shared enrollment; the backend requires owner or billing-manager permissions for shared enrollments.

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 (api_key, password, ...) are masked on reads.

None
shared bool

Create a team-shared enrollment instead of a personal one.

False

cancel

cancel(enrollment_id: str | UUID) -> CustomerEnrollmentCancelResponse

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.

Files

unitysvc.files.Files

Files(client: AuthenticatedClient)

Operations on the customer's account files (/v1/customer/files).

Methods:

list

list(path: str = '', *, scope: FileScope = 'personal', max_keys: int = 100, continuation_token: str | None = None) -> AccountFilesListResponse

List one folder level; keys are relative to the scope root.

response.shared_enabled reports whether the shared scope is available on the customer's plan.

download_url

download_url(key: str, *, scope: FileScope = 'personal', expires_in: int = 900) -> AccountFileDownloadResponse

Presign a download URL for one file (no bytes transferred).

download

download(key: str, dest: str | Path | None = None, *, scope: FileScope = 'personal') -> Path

Download one file to dest (default: its basename in cwd).

Returns the path written. Bytes stream storage → disk directly.

upload

upload(src: str | Path, path: str = '', *, scope: FileScope = 'personal', filename: str | None = None, content_type: str | None = None) -> str

Upload a local file into a folder under the scope root.

Mints a policy-constrained presigned POST from the API, then POSTs the bytes directly to storage. Returns the file's key relative to the scope root ({path}/{filename}). Uploading to an existing key overwrites it, like a home directory.

Secrets

unitysvc.secrets.Secrets

Secrets(client: LowLevelClient)

Operations on the customer's secret store (/v1/customer/secrets).

Methods:

list

list(*, skip: int = 0, limit: int = 100) -> SecretsPublic

List all secrets owned by the authenticated customer.

get

get(name: str) -> SecretPublic

Get a single secret by name.

Metadata for a secret (.value is None — write-only); a variable additionally returns its decrypted .value.

set

set(name: str, value: str, *, sensitive: bool | None = None, description: str | None = None) -> SecretPublic

Set name to value (idempotent — creates or replaces).

Maps to PUT /v1/customer/secrets/{name}. The value is encrypted server-side.

sensitive controls whether this is a secret (write-only; the default) or a variable (its value is returned to authorized callers, e.g. so you can confirm what you stored). It is honored only when the row is created — an existing row cannot switch between secret and variable (attempting to changes raises a 409 ApiError). Leave it None to accept the default (a secret) or preserve an existing row's kind on update.

Parameters:

Name Type Description Default
name str

Secret name (must match ^[A-Z_][A-Z0-9_]*$).

required
value str

Secret value. May be empty.

required
sensitive bool | None

False creates a viewable variable, True an explicit secret, None (default) leaves it unset.

None
description str | None

Author guidance stored on the row; None leaves any existing description untouched.

None

Returns:

Type Description
SecretPublic

SecretPublic metadata. For a variable, .value is populated.

delete

delete(name: str) -> Message

Delete a secret by name. This action cannot be undone.

Aliases

unitysvc.aliases.Aliases

Aliases(client: LowLevelClient)

Operations on the customer's service aliases (/v1/customer/aliases).

Methods:

list

list(*, skip: int = 0, limit: int = 100, name: str | None = None, include_deactivated: bool = False) -> Any

List aliases owned by the authenticated customer.

get

get(alias_id: str | UUID) -> Any

Get a single alias by id.

create

create(body: ServiceAliasCreate | dict[str, Any]) -> Any

Create a new alias.

update

update(alias_id: str | UUID, body: ServiceAliasUpdate | dict[str, Any]) -> Any

Update an existing alias.

switch

switch(identifier: str | UUID, *, target: str | None = None, routing_key: str | None = None, on: bool = True) -> Any

Switch which target routes for an alias — the one-call provider switch.

identifier is an alias name, a full UUID, or a partial UUID. For a name, target (target-path substring) and routing_key (routing-key- value substring) select a specific target; omit both to cycle to the next. on=False turns the current target off.

delete

delete(alias_id: str | UUID) -> Any

Delete an alias by id.

RecurrentRequests

unitysvc.recurrent_requests.RecurrentRequests

RecurrentRequests(client: LowLevelClient)

Operations on the customer's recurrent requests (/v1/customer/recurrent-requests).

Methods:

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.

get

get(request_id: str | UUID) -> RecurrentRequestPublic

Get a single recurrent request by id.

create

create(body: RecurrentRequestCreate | dict[str, Any]) -> RecurrentRequestPublic

Create a new recurrent request.

update

update(request_id: str | UUID, body: RecurrentRequestUpdate | dict[str, Any]) -> RecurrentRequestPublic

Update an existing recurrent request.

trigger

trigger(request_id: str | UUID) -> Any

Force an immediate run of a recurrent request.

delete

delete(request_id: str | UUID) -> Any

Delete a recurrent request by id.

RequestLogs

unitysvc.request_logs.RequestLogs

RequestLogs(client: LowLevelClient)

Operations on the customer's request log (/v1/customer/request-logs).

Methods:

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 event_timestamp.

None
end_time datetime | None

Inclusive upper bound on event_timestamp.

None
user_request_path str | None

Path-prefix filter.

None
error_source str | None

"gateway" or "upstream".

None
error_type str | None

Filter by error type.

None
gateway_source str | None

"apisix" or "backend".

None

get

get(log_id: UUID | str) -> OpsCustomerRequestLogDetail | RequestLogDetail

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).

Preferences

unitysvc.preferences.Preferences

Preferences(client: LowLevelClient)

Operations on the customer's preferences (/v1/customer/preferences).

Methods:

set

set(name: str, value: Any = None) -> UserPublic

Set (or clear, with value=None) one named preference.

Returns the updated user, including the full preference dict — useful for confirming what was actually persisted.

set_notification_destination

set_notification_destination(service: str | None) -> UserPublic

Typed convenience for the "notification-destination" preference.

service is where personal notifications (in-app events routed through notify://user) get forwarded — a service path (e.g. "labs/discord-relay"), or a "b/<name>" broadcast / "e/<CODE>" enrollment shorthand you own. Pass None to clear it (falls back to in-app delivery only).

set_request_log_mode

set_request_log_mode(mode: RequestLogMode | None) -> UserPublic

Typed convenience for the "request-log" preference.

Enable request logging for the authenticated user, or disable it with mode=None. Already-persisted rows remain visible via :meth:unitysvc.request_logs.RequestLogs.list / :meth:~unitysvc.request_logs.RequestLogs.get either way; only future gateway dispatches are affected. Idempotent.

Parameters:

Name Type Description Default
mode RequestLogMode | None

"truncated" — every request is logged with bodies clipped at 8 KB, no S3 upload. "complete" — full request/response bodies are uploaded to S3 so get() can return the full payload (the listing endpoint still returns only the clipped preview, to keep paging cheap). None disables logging.

required

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

StreamEvent(kind: str, parsed: Any = None, raw: bytes = b'', text: str | None = None)

One frame from a streaming response body.

Attributes:

Name Type Description
kind str

"sse" | "ndjson" | "line" | "bytes" | "done". See :meth:StreamingResponse.iter_events for the taxonomy.

parsed Any

JSON-decoded payload for "sse" / "ndjson", else None.

raw bytes

The raw bytes of this frame (the full SSE frame for "sse", the line including delimiter-stripped bytes for "ndjson" / "line", or the chunk for "bytes").

text str | None

Decoded UTF-8 text for "line" events; None otherwise.

StreamingResponse

StreamingResponse(httpx_client: Client, method: str, url: str, kwargs: dict[str, Any])

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
response: Response

The underlying httpx.Response. Only valid inside the with block.

Methods:

iter_bytes
iter_bytes(chunk_size: int | None = None) -> Iterator[bytes]

Yield raw body chunks as they arrive.

iter_lines
iter_lines() -> Iterator[str]

Yield \n-delimited decoded text lines.

iter_events
iter_events() -> Iterator[StreamEvent]

Yield :class:StreamEvent objects, discriminated by Content-Type.

  • text/event-stream"sse" per frame, "done" on data: [DONE]. Frames split across TCP chunks are reassembled before yielding.
  • application/x-ndjson / application/jsonl"ndjson" per line.
  • text/*"line" per line (text in event.text).
  • anything else → "bytes" per chunk.

AsyncStreamingResponse

AsyncStreamingResponse(httpx_client: AsyncClient, method: str, url: str, kwargs: dict[str, Any])

Async sibling of :class:StreamingResponse. async with to enter.

Methods:

iter_events async
iter_events() -> AsyncIterator[StreamEvent]

Async sibling of :meth:StreamingResponse.iter_events.

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: LowLevelClient, *, 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 LowLevelClient

Low-level authenticated client (injected by :class:~unitysvc.Client).

required
path str

Gateway request path (same shape as service.dispatch(path=...)), e.g. v1/chat/completions.

required
routing_key dict[str, Any] | None

Optional routing key the gateway would match against interface rules (e.g. {"model": "gpt-4"}).

None
gateway str

"api" (default), "s3", or "smtp". Picks which gateway prefix the path belongs to.

'api'
strategy str | None

Override the group's configured routing strategy (e.g. "by_price", "lowest_latency").

None

Returns:

Name Type Description
A ResolveResponse

class:~unitysvc._generated.models.resolve_response.ResolveResponse

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

APIError(message: str, *, status_code: int, detail: Any = None, response_body: bytes | None = None)

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 ErrorResponse), or the raw text if not JSON.

response_body

Raw response bytes, useful for debugging.

AuthenticationError

AuthenticationError(message: str, *, status_code: int, detail: Any = None, response_body: bytes | None = None)

Bases: APIError

401 Unauthorized. The API key is missing, invalid, or expired.

PermissionError

PermissionError(message: str, *, status_code: int, detail: Any = None, response_body: bytes | None = None)

Bases: APIError

403 Forbidden. The authenticated customer cannot perform this action.

NotFoundError

NotFoundError(message: str, *, status_code: int, detail: Any = None, response_body: bytes | None = None)

Bases: APIError

404 Not Found. The requested resource does not exist for this customer.

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.

ConflictError

ConflictError(message: str, *, status_code: int, detail: Any = None, response_body: bytes | None = None)

Bases: APIError

409 Conflict. The request conflicts with server state (e.g. duplicate name).

RateLimitError

RateLimitError(message: str, *, status_code: int, detail: Any = None, response_body: bytes | None = None)

Bases: APIError

429 Too Many Requests. Retry after the backoff window.

ServerError

ServerError(message: str, *, status_code: int, detail: Any = None, response_body: bytes | None = None)

Bases: APIError

5xx. The server encountered an error. Safe to retry idempotent requests.