Skip to main content

sstudio Python SDK

Python client and command-line interface for model lifecycle APIs.

Requirements​

  • Python 3.8+
  • An API key
  • An API base URL

Installation​

pip install sstudio

This package installs both the Python SDK and the sstudio command.

Quick Start​

import os
from sstudio import SmartStudioClient

with SmartStudioClient(
api_key=os.environ["SSTUDIO_PLATFORM__API_KEY"],
base_url=os.environ["SSTUDIO_PLATFORM__API_ENDPOINT"],
) as client:
me = client.me()
models = client.models.list(page=1, page_size=20)
print(me)
print(models)

The context manager closes the underlying HTTP client automatically.

Authentication​

Only the API key and API base URL are required. The SDK manages the two-step authentication flow internally:

StepBehavior
LoginExchanges the API key for a short-lived bearer token.
RequestsAdds the bearer token to authenticated API requests.
RefreshRefreshes authentication and retries a safe request once after a 401.

The API key is never sent to pre-signed object storage URLs.

Client Configuration​

import os

client = SmartStudioClient(
api_key=os.environ["SSTUDIO_PLATFORM__API_KEY"],
base_url=os.environ["SSTUDIO_PLATFORM__API_ENDPOINT"],
timeout=30.0,
max_retries=2,
default_headers={"X-Request-Source": "integration"},
)

The optional on_token_refresh callback is intended for a host application that already has an approved secret store. It is omitted here so the example is runnable and does not encourage saving bearer tokens to ordinary files.

OptionRequiredDescription
api_keyYesAPI key exchanged for a bearer token.
base_urlYes*API origin or console URL. May be supplied by environment variable.
tokenNoExisting bearer token managed by the host application.
timeoutNoRequest timeout in seconds. Default: 30.
max_retriesNoSafe-request retry count. Default: 2.
default_headersNoAdditional string headers for API requests.
on_token_refreshNoCallback invoked when a new bearer token is issued. Store it only in an approved secret store; never log it.

base_url can also be configured with:

export SSTUDIO_PLATFORM__API_ENDPOINT="https://your-host.example"
export SSTUDIO_PLATFORM__API_KEY="your-api-key"

The CLI additionally accepts SSTUDIO_PLATFORM__API_KEY. Constructor arguments take precedence, and the SDK has no implicit network endpoint. An environment origin, a /msp-console URL, and an explicit /msp-api URL are all normalized to the same API base path.

Return Values and Errors​

Resource methods return the response envelope's data value:

{
"code": 200,
"message": "success",
"data": {"id": 42, "status": "RUNNING"}
}

For this response, client.deployments.get(42) returns the object inside data. Methods without a result return None; text endpoints such as client.deployments.yaml(42) return str. Use client.request(...) only when the complete envelope is required.

from sstudio import APIError, AuthenticationError, ValidationError

try:
deployment = client.deployments.get(42)
except AuthenticationError:
print("The API key or session is invalid")
except ValidationError as exc:
print(exc.error_code, exc.details)
except APIError as exc:
print(exc.message)

API exceptions preserve code, message, error_code, and details when provided by the server.

Module Overview​

ModuleAccessorTypical operations
Identityclient.me()Current authenticated user
Clustersclient.clustersCluster list, capacity, history, resource holds
Modelsclient.modelsModel catalog and deployment capabilities
My Modelsclient.my_modelsEnd-to-end model upload and asset lifecycle
Datasetsclient.datasetsEnd-to-end upload, list, preview, download, lifecycle
AI Datasetclient.datasets.preparationsPreparation, labeling, resource preview, download
Deploymentsclient.deploymentsPreflight, create, lifecycle, events, YAML
Trainingclient.trainingPreflight, create, wait, cancel, artifacts
Evaluationsclient.evaluationsPreflight, create, wait, reports, artifacts
Jobsclient.jobsGeneric job status, logs, wait, cancel
API Keysclient.keysPlatform API key lifecycle
Provider Keysclient.provider_keysBYOK provider credentials and connectivity tests
Usageclient.usageUsage records, summaries, trends
Observabilityclient.observabilityCluster, service, and workload metrics

Use the API Map to move between the Python, TypeScript, and CLI references.

Module Examples​

The following examples assume an initialized client.

Identity​

me = client.me()

Clusters​

clusters = client.clusters.list()
capacity = client.clusters.capacity(1)
history = client.clusters.timeseries(1, limit=60)
holds = client.clusters.holds(cluster_id=1)

Models​

models = client.models.list(keyword="Qwen", page=1, page_size=20)
model = client.models.get("qwen3-4b")
capabilities = client.models.deployment_capabilities(
"qwen3-4b",
cluster_id="1",
)

My Models​

upload(...) validates model files, hashes the directory, transfers objects, completes the upload, and returns the registered model asset.

model = client.my_models.upload(
"./model",
name="example-model",
model_type="LLM",
)
model_id = model["id"]

page = client.my_models.list(page=1, page_size=20)
detail = client.my_models.get(model_id)
client.my_models.update(model_id, {"description": "production candidate"})

Datasets​

dataset = client.datasets.upload(
"./train.jsonl",
name="example-training-dataset",
dataset_type="training",
training_category="sft-llm",
)
dataset_id = dataset["id"]

preview = client.datasets.preview(dataset_id, limit=20)
page = client.datasets.list(page_num=1, page_size=20)
download = client.datasets.download_url({"datasetId": dataset_id, "fileIndex": 0})

AI Dataset Preparations​

clusters = client.datasets.preparations.cluster_options()
provider_keys = client.datasets.preparations.available_provider_keys()
tasks = client.datasets.preparations.list({"pageNum": 1, "pageSize": 20})
task = client.datasets.preparations.get(id=123)

Create and action payloads are passed as dictionaries matching the API contract:

preview = client.datasets.preparations.preview(resource_preview_request)
task = client.datasets.preparations.create(preparation_request)
client.datasets.preparations.generate_rules(id=task["id"])
rules_ready = client.wait_for_dataset_preparation(
task["id"], until="rules_ready"
)
client.datasets.preparations.start_labeling(labeling_request)
completed = client.wait_for_dataset_preparation(task["id"])

Deployments​

The workflow automatically selects the Model Profile or model-asset creation route from the request's model reference.

request = {
"name": "example-deployment",
"modelSource": "gallery",
"modelName": "Qwen3-4B-Instruct-2507-FAST",
"backend": "sglang",
"servingMode": "standard",
"gpuType": "L20",
"replicas": 1,
"clusterId": 1,
}

preview = client.deployments.preview(request)
if preview.get("creatable"):
deployment = client.deployments.create(request)
running = client.wait_for_deployment(deployment["id"])

Lifecycle and diagnostics:

page = client.deployments.list(page=1, page_size=20)
events = client.deployments.events(42)
rendered_yaml = client.deployments.yaml(42)
client.deployments.stop(42)
client.deployments.preview_restart(42)
client.deployments.restart(42)

Training​

outputModelName is a suffix, not the complete asset name. Its maximum length depends on the selected base model because the final deployable name is <base>-FT-<suffix>; use the limit returned by the active capability.

request = {
"clientToken": "training-request-001",
"displayName": "example-training",
"outputModelName": "example-output",
"recipeId": "recipe-id",
"recipeVersion": "recipe-version",
"baseModelRef": {"type": "recipe_model", "id": "model-id"},
"datasetRefs": [{"datasetId": "dataset-id", "role": "train"}],
"placement": {"clusterId": "1", "resourceSpecId": "resource-spec-id"},
"params": {},
}

client.training.preview({"clusterId": 1, "resourceSpecId": "resource-spec-id"})
job = client.training.create(request)
completed = client.wait_for_training_job(job["jobId"])
artifact = client.training.artifact_download_url(
completed["artifacts"][0]["artifactId"]
)

Evaluations​

request = {
"kind": "benchmark",
"modelType": "LLM",
"models": [{
"type": "service",
"msp_api_key_id": "7",
"service_id": "42",
}],
"dataset": "evaluation-dataset",
"maxSamples": 100,
"clusterId": 1,
}

client.evaluations.preview({"clusterId": 1})
job = client.evaluations.create(request)
client.wait_for_evaluation_job(job["jobId"])
report = client.evaluations.report(job["jobId"])

Jobs​

jobs = client.jobs.list(type="train", status="RUNNING", page=1, page_size=20)
job = client.jobs.get("job-id")
logs = client.jobs.logs("job-id", tail=200)
client.wait_for_job("job-id")

API Keys​

keys = client.keys.list()
created = client.keys.create({
"keyValue": "sk-created-by-caller",
"description": "automation key",
"isActive": True,
})
key_id = str(created["id"])
plaintext = client.keys.reveal(key_id)
client.keys.update(key_id, {"description": "renamed key", "isActive": True})

Treat the value returned by reveal(...) as a secret and never log it.

Provider Keys​

providers = client.provider_keys.providers()
keys = client.provider_keys.list()
created = client.provider_keys.create({
"provider": "example-provider",
"apiKey": "provider-api-key",
"description": "integration credential",
})
result = client.provider_keys.test(created["id"])
client.provider_keys.change_status(created["id"], {"status": 1})

Usage​

start_seconds = 1782864000
end_seconds = 1785542400

summary = client.usage.summary(start_date=start_seconds, end_date=end_seconds)
records = client.usage.list(
start_date=start_seconds,
end_date=end_seconds,
page=1,
page_size=20,
)
trend = client.usage.trend(
start_date=start_seconds,
end_date=end_seconds,
granularity="day",
)

Observability​

overview = client.observability.cluster_overview(1)
services = client.observability.services(cluster_id=1)
snapshot = client.observability.service_snapshot(42)
series = client.observability.service_timeseries(
42,
range_hours=1,
max_points=120,
)

Detailed API Reference​

Use the expandable Python SDK section in the left navigation. Every public method has a dedicated module page with its purpose, request parameters or body, response shape, examples, and operational constraints.