Skip to main content

Python SDK for the Convox API

Project description

Python SDK for the Convox API.

Installation

pip install convox

Quick Start

from convox import ConvoxClient

client = ConvoxClient(
    host="console.convox.com",
    api_key="your-deploy-key",
    rack="org/rack-name",          # required for console connections
)

# List apps
for app in client.apps.list():
    print(f"{app.name}: {app.status}")

# Get app details
app = client.apps.get("myapp")
print(f"Release: {app.release}, Locked: {app.locked}")

Authentication

For console-managed racks the api_key is a deploy key generated in the Convox console (Organization > Deploy Keys). Deploy keys are the recommended auth method for programmatic and SDK usage. The examples below all use deploy keys.

Three options, in order of precedence:

1. Explicit credentials (recommended)

client = ConvoxClient(
    host="console.convox.com",
    api_key="your-deploy-key",
    rack="org/rack-name",        # required for console-managed racks
)

2. Environment variables

Set CONVOX_HOST, CONVOX_PASSWORD (deploy key), and CONVOX_RACK:

client = ConvoxClient.from_env()

3. CLI config file

Reads the auth file written by convox login (~/.config/convox/auth for v3, ~/.convox/auth for v2). This is a convenience for local development when you have already authenticated via the CLI -- it reads whatever credential is stored for the given host, whether that is a CLI session token or a deploy key you placed there manually.

# Console-managed rack — specify both host and rack
client = ConvoxClient.from_cli_config(
    host="console.convox.com",       # auth file lookup key
    rack="org/rack-name",            # rack to target
)

# Direct rack connection (host and rack are the same)
client = ConvoxClient.from_cli_config(rack="rack.example.com")

API Reference

Apps

# List, get, create, delete
apps = client.apps.list()
app = client.apps.get("myapp")
app = client.apps.create("myapp")
client.apps.delete("myapp")

# Update (lock/unlock, set parameters)
client.apps.update("myapp", lock=True)
client.apps.update("myapp", parameters={"BuildCpu": "512"})

# Cancel in-progress operation
client.apps.cancel("myapp")

Builds

builds = client.builds.list("myapp")
build = client.builds.get("myapp", "BABCDEF")
build = client.builds.create("myapp", "https://example.com/source.tgz",
                              description="v2.0 release")

Releases

releases = client.releases.list("myapp")
release = client.releases.get("myapp", "RABCDEF")

# Promote a release to production
client.releases.promote("myapp", "RABCDEF")

# Rollback to a previous release
client.releases.rollback("myapp", "RPREVIOUS")

Environment Variables

# Get current env
env = client.environment.get("myapp")
print(env)  # {"DATABASE_URL": "postgres://...", "SECRET_KEY": "..."}

# Set env vars (creates a new release)
release = client.environment.set("myapp", {"KEY": "value", "OTHER": "val"})

# Unset env vars (creates a new release)
release = client.environment.unset("myapp", "KEY")

Services

services = client.services.list("myapp")
client.services.update("myapp", "web", count=3, memory=1024)
client.services.restart("myapp", "web")

Processes

processes = client.processes.list("myapp")
process = client.processes.get("myapp", "proc-abc123")
client.processes.stop("myapp", "proc-abc123")

Resources

# App-scoped resources
resources = client.resources.list("myapp")
resource = client.resources.get("myapp", "database")

# System-scoped resources
all_resources = client.resources.system_list()
client.resources.system_create("postgres", name="mydb")
client.resources.system_link("mydb", "myapp")

System

system = client.system.get()
print(f"{system.name} v{system.version} ({system.provider})")

capacity = client.system.capacity()

Low-Level API

Escape hatch for endpoints not covered by resource methods:

# Equivalent to `convox api get /apps`
data = client.api.get("/apps")

# POST with form data
data = client.api.post("/apps", data={"name": "newapp"})

Error Handling

All API errors raise typed exceptions:

from convox import (
    ConvoxAPIError,        # Base for all API errors
    ConvoxAuthError,       # 401 - bad credentials
    ConvoxForbiddenError,  # 401 - insufficient permissions
    ConvoxNotFoundError,   # 404 - resource not found
    ConvoxValidationError, # 400 - invalid input
    ConvoxConflictError,   # 409 - already exists / locked
    ConvoxServerError,     # 500 - server error
    ConvoxConnectionError, # Network failure
    ConvoxTimeoutError,    # Request timeout
)

try:
    app = client.apps.get("myapp")
except ConvoxNotFoundError:
    print("App does not exist")
except ConvoxConflictError:
    print("App is locked")
except ConvoxAPIError as e:
    print(f"API error {e.status_code}: {e.message}")
    print(f"Request ID: {e.request_id}")  # for support tickets

Retry Configuration

The SDK retries on 429 (rate limit) and 502/503/504 (gateway errors) with exponential backoff:

from convox import ConvoxClient, RetryConfig

client = ConvoxClient(
    host="rack.example.com",
    api_key="key",
    retry=RetryConfig(
        max_retries=5,           # default: 3
        backoff_base=2.0,        # default: 1.0
        backoff_max=60.0,        # default: 30.0
        retry_on_500=True,       # default: False (500s may be permanent)
    ),
)

Disable retries:

client = ConvoxClient(host="...", api_key="...", retry=RetryConfig(max_retries=0))

Timeouts

The default timeout is 30 seconds. Most API operations complete well within this limit, since build creation (builds.create) returns immediately after dispatching the build to a Kubernetes pod.

The one exception is builds.import_build(), which is synchronous — the server reads the entire gzip archive and pushes every service image to the container registry before responding. This method defaults to a 1800-second (30-minute) per-request timeout, independent of the client-wide default:

# Uses the 30-minute default automatically
build = client.builds.import_build("myapp", tarball_bytes)

# Override with a custom timeout if needed
build = client.builds.import_build("myapp", tarball_bytes, timeout=3600)

You can also pass a per-request timeout to the low-level API:

data = client.api.post("/apps/myapp/builds/import", content=tarball, timeout=600)

Streaming

The stream() method returns the raw httpx.Response without checking for error status codes. This is intentional: streaming endpoints (logs, build output) may send partial data before an error occurs.

response = client.stream("GET", "/apps/myapp/logs", params={"follow": "true"})
try:
    if response.status_code >= 400:
        print(f"Error: {response.status_code}")
    else:
        for line in response.iter_lines():
            print(line)
finally:
    response.close()

CLI Comparison

CLI Command SDK Equivalent
convox apps client.apps.list()
convox apps info -a myapp client.apps.get("myapp")
convox apps create myapp client.apps.create("myapp")
convox apps delete myapp client.apps.delete("myapp")
convox builds -a myapp client.builds.list("myapp")
convox releases -a myapp client.releases.list("myapp")
convox releases promote RABCDEF -a myapp client.releases.promote("myapp", "RABCDEF")
convox env -a myapp client.environment.get("myapp")
convox env set KEY=val -a myapp client.environment.set("myapp", {"KEY": "val"})
convox env unset KEY -a myapp client.environment.unset("myapp", "KEY")
convox api get /apps client.api.get("/apps")

Contributing

# Install dev dependencies
pip install -e ".[dev]"

# Run unit tests (mocked, no rack needed)
pytest tests/

# Run integration tests (requires a live rack)
CONVOX_HOST=console.convox.com \
CONVOX_PASSWORD=your-deploy-key \
CONVOX_RACK=org/rack-name \
pytest integration_tests/ -v

# Lint and format
ruff check .
ruff format .

# Type check
mypy src/

License

Apache 2.0

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

convox-0.1.0.tar.gz (36.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

convox-0.1.0-py3-none-any.whl (29.8 kB view details)

Uploaded Python 3

File details

Details for the file convox-0.1.0.tar.gz.

File metadata

  • Download URL: convox-0.1.0.tar.gz
  • Upload date:
  • Size: 36.6 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for convox-0.1.0.tar.gz
Algorithm Hash digest
SHA256 f0c053a30eaadfe56adc20b847b5e8880b4f70ec334f9ce2dbafcd52012f49d8
MD5 0bf9720864e5e5cf3d09e1ef4f0000bf
BLAKE2b-256 a48a9a1b42cb739ee10a6867b3d1a4593505f989261d74374959fce9319a0384

See more details on using hashes here.

File details

Details for the file convox-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: convox-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 29.8 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for convox-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d31418affcb7d650318a16d6e4714cfd6e063b8cccfd447f70b6d9be1831ffcd
MD5 d1615463cf1bbdc87b049cf046497d09
BLAKE2b-256 15400cfdb338905bfe7975a4f5ea3f8ed10b754afe3dab91df294395f8f462c2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page