openstead
Developer tools & integrations

Python SDK

Use synchronous and asynchronous typed Python clients for the Openstead core API.

Suggest a change

The Openstead Python SDK supports Python 3.10 and newer, with HTTPX transport and Pydantic models. Openstead and AsyncOpenstead expose the same public core resources.

Install

Install the Openstead SDK from the private Python repository. Your GitHub identity needs repository access and an authenticated Git credential helper. Contact Openstead support to request access if the repository is unavailable.

python -m pip install "git+https://github.com/Layerrail/openstead-python.git@32e1ccc913b2dd7ad3d964da46bd63f92e2a6de0"

For a local checkout, run python -m pip install . from the repository directory. Pin a reviewed source commit in production dependency files. The SDK is not published on PyPI; never insert a GitHub token into an installation command or dependency file.

The examples below use the Openstead source version. Existing installations can keep using the runivo import and Runivo / AsyncRunivo compatibility aliases after upgrading. OPENSTEAD_API_KEY takes precedence, with RUNIVO_API_KEY retained as a fallback.

Read services

Set OPENSTEAD_API_KEY in your secret environment and OPENSTEAD_WORKSPACE_ID to its workspace UUID.

import os
from openstead import Openstead

with Openstead() as client:
    workspace_id = os.environ["OPENSTEAD_WORKSPACE_ID"]
    workspace = client.workspaces.get(workspace_id=workspace_id).workspace
    print(workspace.name)

    for service in client.services.iter(workspace_id=workspace_id):
        print(service.name, service.status, service.url)

The default API root is https://api.openstead.tech/api/v1. Pass api_key= explicitly to override the environment. Reuse a client in long-lived applications, and close it with a context manager or close().

Async usage

import asyncio
import os
from openstead import AsyncOpenstead

async def main() -> None:
    async with AsyncOpenstead() as client:
        async for project in client.projects.iter(
            workspace_id=os.environ["OPENSTEAD_WORKSPACE_ID"],
        ):
            print(project.id, project.name)

asyncio.run(main())

Await endpoint methods; use async for for iterators. Use async with or aclose() to close an asynchronous client.

Create a project

This creates configuration and requires a write key:

import os
from openstead import Openstead
from openstead.models import ProjectCreate

with Openstead() as client:
    response = client.projects.create(
        workspace_id=os.environ["OPENSTEAD_WORKSPACE_ID"],
        data=ProjectCreate(name="example-project", color="violet"),
        idempotency_key="create-example-project-001",
    )
    print(response.project.id)

data= accepts typed models or mappings with API field names. Models expose Python snake_case attributes, such as live_deployment_id. Serialize wire names with model_dump(by_alias=True, mode="json") when needed.

Resources and helpers

ResourceMethods
catalogget()
workspacesget()
projectslist(), iter(), get(), create(), update(), delete()
serviceslist(), iter(), get(), create(), update(), delete(), archive(), restore(), action()
variableslist(), iter(), create(), update(), delete(), reveal()
deploymentslist(), iter(), get(), create(), cancel(), rollback(), wait()
operationsget(), wait()
logslist(), iter(), tail()

Use client.get_openapi() to retrieve the public contract. Endpoint responses keep their named envelope; iterator and wait helpers yield or return the contained model.

Poll an existing deployment

import os
from openstead import DeploymentFailed, PollTimeout, Openstead

with Openstead() as client:
    try:
        deployment = client.deployments.wait(
            workspace_id=os.environ["OPENSTEAD_WORKSPACE_ID"],
            service_id=os.environ["OPENSTEAD_SERVICE_ID"],
            deployment_id=os.environ["OPENSTEAD_DEPLOYMENT_ID"],
            timeout=300.0,
            poll_interval=2.0,
        )
        print(deployment.status)
    except DeploymentFailed:
        print("Review this deployment's logs before deploying again.")
    except PollTimeout:
        print("The wait ended. Read the existing deployment for its current state.")

Waits default to 600 seconds and a two-second interval. A local cancellation or timeout ends observation, not the remote deployment. operations.wait() returns at complete and raises OperationFailed on failure.

Retry configuration and errors

The client defaults to a 20-second request timeout, at most two retries, and a 30-second retry window. Configure timeout, max_retries, and max_retry_elapsed at construction. Supported writes receive a key automatically; provide a durable idempotency_key for retries across separate calls.

import os
from openstead import APIError, Openstead, TransportError

try:
    with Openstead(max_retries=2) as client:
        client.projects.list(workspace_id=os.environ["OPENSTEAD_WORKSPACE_ID"], limit=100)
except APIError as exc:
    print(exc.status_code, exc.code, exc.request_id)
except TransportError:
    print("The API request could not complete within its retry limits.")

Use APIError.errors only when you need the server's detailed messages. Do not log whole requests, responses, or secret models. Secret reveal is an explicit audited operation with no automatic retries. See retry rules and log reading.

Need a hand? Contact Openstead support.

On this page