Skip to content

Python SDK

The SDK exposes two clients with identical method names — Meshive (synchronous) and AsyncMeshive (asyncio). Both read the same credentials and configuration as the CLI (see Authentication).

from meshive import Meshive
with Meshive() as client: # reads MESHIVE_API_KEY
me = client.me()
print(me.email, me.user_role)
for ws in client.list_workspaces():
print(ws.namespace_name, ws.status)
pods = client.list_pods("my-workspace")
pod = client.get_pod(pods[0].pod_name, "my-workspace")
print(pod.status, pod.raw) # .raw holds the full payload
# host view: the machines you contribute to the network
machines = client.list_machines()
for m in machines:
print(m.machine_id, m.status, m.gpu_count, m.gpu_model)
machine = client.get_machine(machines[0].machine_id)
print(machine.earning_hourly, machine.raw)

Using the client as a context manager (with / async with) ensures the underlying HTTP connection is closed. Otherwise, call client.close() (or await client.close()) yourself.

Meshive(api_key=None, *, timeout=30.0)
AsyncMeshive(api_key=None, *, timeout=30.0)

With no arguments, credentials resolve in the usual order (explicit argument › environment variable › meshive login file). You can also pass the key explicitly:

client = Meshive(api_key="meshive_xxxxxxxx")

timeout is the per-request timeout in seconds (default 30.0). If no API key can be resolved, the first request raises ConfigurationError.

Both clients expose the same methods (await them on AsyncMeshive):

MethodReturnsDescription
me()WhoAmIThe current API key’s owner.
list_workspaces()list[Workspace]Workspaces you can access.
list_pods(workspace)list[Pod]Pods in a workspace (by ID).
get_pod(pod_name, workspace)PodA single pod.
list_machines()list[Machine]Machines you host.
get_machine(machine_id)MachineA single machine.

Responses are parsed into lightweight dataclasses. Frequently used scalar fields are typed; deeply nested structures aren’t enumerated — the full original payload is preserved on .raw, so the SDK keeps working even when the backend adds fields.

FieldTypeNotes
emailstr
usernamestr | None
user_rolestr
rawdictFull payload.
FieldTypeNotes
namespace_namestrID — pass to list_pods / get_pod.
workspace_namestrDisplay label.
descriptionstr
member_countint
statusstr
price_per_hourstr
resourcesWorkspaceResources.pod, .storage, .serverless counts.
created_at / updated_atdatetime | None
rawdictFull payload.
FieldTypeNotes
pod_namestrID — pass to get_pod.
namespace_namestrOwning workspace ID.
user_aliasstrDisplay label.
statusstr
rental_typestrspot / demand.
price_per_hourstr
is_maintenancebool
created_atdatetime | None
rawdictFull payload — machine, template, request, linked storages, …
FieldTypeNotes
machine_idstrID — pass to get_machine.
namestrDisplay label.
machine_typestrgpu / cpu / storage.
statusstr
gpu_modelstrEmpty for cpu/storage machines.
gpu_countint
earning_hourlyfloat
uptime_ratefloat0.01.0.
host_tierstr
rawdictFull payload — specs, full state, pod uses, …

All SDK errors subclass MeshiveError:

ExceptionWhen
ConfigurationErrorNo API key could be resolved (raised before any request).
AuthenticationError401 — missing/invalid/expired key, or an inactive account.
PermissionDeniedError403 — the key lacks the required scope.
NotFoundError404 — the resource doesn’t exist.
RateLimitError429 — rate limit exceeded. Exposes .retry_after (seconds, may be None).
MeshiveAPIErrorAny other 4xx/5xx.

MeshiveAPIError (and its subclasses) carry .status_code, .title, .message, and .raw (the parsed response body).

from meshive import Meshive, MeshiveError, RateLimitError, NotFoundError
try:
with Meshive() as client:
pod = client.get_pod("does-not-exist", "my-workspace")
except NotFoundError as err:
print("no such pod:", err.message)
except RateLimitError as err:
print("slow down; retry after", err.retry_after, "s")
except MeshiveError as err:
print("request failed:", err)
from meshive import (
Meshive, AsyncMeshive, # clients
WhoAmI, Workspace, WorkspaceResources, Pod, Machine, # models
MeshiveError, ConfigurationError, MeshiveAPIError, # errors
AuthenticationError, PermissionDeniedError,
NotFoundError, RateLimitError,
__version__,
)