Skip to main content

capawesome-cloud

PyPI version PyPI downloads license

Python SDK for the Capawesome Cloud API.

It provides a fully typed, synchronous interface for managing organizations, apps, live update channels and deployments, native builds, app store destinations, and more.

Note: The Capawesome Cloud API is still in development and may change without notice. Response types intentionally expose only the most relevant properties to minimize breaking changes.

SDKs

Official SDKs for the Capawesome Cloud API:

Language Package Repository
Node.js @capawesome/cloud-sdk cloud-node
Python capawesome-cloud cloud-python

Installation

pip install capawesome-cloud

Requirements: Python 3.9 or later.

Getting started

Create an API token in the Capawesome Cloud Console and pass it to the client (or set the CAPAWESOME_CLOUD_TOKEN environment variable, with CAPAWESOME_TOKEN accepted as a fallback):

from capawesome_cloud import CapawesomeCloud

client = CapawesomeCloud(token="cap_...")

for app in client.apps.list():
    print(app.id, app.name)

The client holds a connection pool, so reuse a single instance. Use it as a context manager (or call client.close()) to release connections when done:

with CapawesomeCloud(token="cap_...") as client:
    ...

Configuration

Option Type Default Description
token str CAPAWESOME_CLOUD_TOKEN env var API token used to authenticate.
base_url str https://api.cloud.capawesome.io Base URL of the API (for self-hosting/testing).
timeout float 30.0 Request timeout in seconds.
max_retries int 2 Retries with exponential backoff. 429 is retried for any request; network/5xx failures are retried only for idempotent methods (GET/PUT/DELETE), never POST/PATCH.
backoff_factor float 0.5 Base delay for the retry backoff.
http_client httpx.Client None Bring your own pre-configured httpx.Client.

Usage

Resources mirror the API's path hierarchy. App-scoped resources are nested under client.apps.*, organization-scoped resources under client.organizations.*; top-level resources are on the client directly (e.g. client.jobs). Every app-scoped method takes app_id as its first argument, every organization-scoped method organization_id.

Organizations

organizations = client.organizations.list()
organization = client.organizations.get(organization_id)
members = client.organizations.members.list(organization_id)

# Invite a new member
client.organizations.invitations.create(
    organization_id, email="jane@example.com", role="member"
)

# Group apps and members in a team
team = client.organizations.teams.create(organization_id, name="Mobile")
client.organizations.teams.apps.create(organization_id, team.id, app_id=app_id)

Apps

apps = client.apps.list()
app = client.apps.get(app_id)
created = client.apps.create(name="My App", type="capacitor")
client.apps.update(app_id, name="Renamed App")
client.apps.delete(app_id)

Live updates

# Create a channel
channel = client.apps.channels.create(app_id, name="production")

# Pause / resume a channel
client.apps.channels.pause(app_id, channel.id)
client.apps.channels.resume(app_id, channel.id)

Deployments

Promote a build to a channel (live updates) or a destination (app store publishing):

# Roll out a live update to half of the devices on a channel
client.apps.deployments.create(
    app_id,
    app_build_id=app_build_id,
    app_channel_name="production",
    rollout_percentage=0.5,
)

# Publish a native build to an app store with localized release notes
client.apps.deployments.create(
    app_id,
    app_build_id=app_build_id,
    app_destination_name="Google Play",
    release_notes={
        "default": "Bug fixes and performance improvements.",
        "de-DE": "Fehlerbehebungen und Leistungsverbesserungen.",
    },
)

Git repositories

Native builds are created from the repository an app is linked to:

connection = client.organizations.git_connections.list_page(organization_id, limit=1)[0]
repositories = client.organizations.git_connections.list_repositories(
    organization_id, connection.id
)

client.apps.repository.set(app_id, git_connection_id=connection.id, path=repositories[0].path)

Native builds

build = client.apps.builds.create(app_id, platform="ios", git_ref="main")

# Poll the job that processes the build until it finishes
job = client.jobs.wait(build.job_id)
print(job.status)

for log in client.jobs.logs(job.id):
    print(log.payload)

# Explain a failure
if job.status == "failed":
    print(client.jobs.get_failure_summary(job.id).summary)

Build artifacts

Binary downloads return bytes:

data = client.apps.builds.artifacts.download(app_id, build_id, artifact_id)
with open("artifact.ipa", "wb") as file:
    file.write(data)

You can also obtain a signed, time-limited download URL:

result = client.apps.builds.artifacts.get_download_url(app_id, build_id, artifact_id)
print(result["url"])

Certificates

file may be a path, raw bytes, or an open binary file object:

import os

certificate = client.apps.certificates.create(
    app_id,
    name="Distribution Certificate",
    platform="ios",
    type="production",
    file="distribution.p12",
    password=os.environ["CERT_PASSWORD"],
)

Environments, secrets & variables

environment = client.apps.environments.create(app_id, name="production")

client.apps.environments.secrets.create(
    app_id,
    environment.id,
    key="API_KEY",
    value=os.environ["API_KEY"],
)

client.apps.environments.variables.create(
    app_id,
    environment.id,
    key="API_URL",
    value="https://api.example.com",
)

Pagination

List methods return an iterator that lazily pages through all results:

for device in client.apps.devices.list(app_id):
    print(device.id, device.app_version_name)

# Collect everything into a list
channels = client.apps.channels.list(app_id).to_list()

To fetch a single page (for manual offset control), use list_page():

page = client.apps.channels.list_page(app_id, limit=20, offset=0)

Responses

Responses are typed Pydantic models. App-scoped models are prefixed with App (AppChannel, AppWebhook, AppBuild, ...) to match the API's entity names. Only the most relevant fields are declared; any additional fields the API returns are still accessible (e.g. via model_dump()) but are not part of the public contract and should not be relied upon.

channel = client.apps.channels.get(app_id, channel_id)
print(channel.name, channel.created_at)   # documented fields
print(channel.model_dump())               # full raw payload, incl. extra fields

Clearing fields

Update methods only send the arguments you pass. To clear a nullable field, pass None; omit the argument to leave it unchanged.

# Pin a device to a channel
client.apps.devices.update(app_id, device_id, forced_app_channel_id="ch_123")

# Unpin it again (sends null)
client.apps.devices.update(app_id, device_id, forced_app_channel_id=None)

Available resources

Resource Description
client.apps Create, read, update, delete and transfer apps.
client.apps.channels Manage live update channels (incl. pause/resume).
client.apps.deployments Promote builds to channels or destinations.
client.apps.builds Trigger and manage native builds.
client.apps.builds.artifacts List and download build artifacts.
client.apps.build_sources Register and download native build sources.
client.apps.certificates Manage signing certificates.
client.apps.destinations Manage app store publishing destinations.
client.apps.environments Manage environments, secrets and variables.
client.apps.automations Manage build automations.
client.apps.devices Manage registered devices.
client.apps.webhooks Manage app webhooks.
client.apps.configurations Manage native app configurations.
client.apps.repository Link an app to a Git repository.
client.organizations Create, read and update organizations.
client.organizations.members Manage organization members.
client.organizations.invitations Invite users to an organization.
client.organizations.teams Manage teams and their apps and members.
client.organizations.license_keys Manage license keys for Insiders packages.
client.organizations.git_connections Manage Git connections and browse repositories.
client.jobs Inspect background jobs and their logs.
client.users Access the authenticated user.

Error handling

Any non-2xx response is raised as a CapawesomeCloudError, carrying the HTTP status, the message from the API, and the raw body:

from capawesome_cloud import CapawesomeCloud, CapawesomeCloudError

client = CapawesomeCloud(token="cap_...")

try:
    client.apps.get("unknown")
except CapawesomeCloudError as error:
    print(error.status)       # 404
    print(error.status_text)  # "Not Found"
    print(error.message)      # "App not found."
    print(error.body)         # {"message": "App not found."}

Network failures raise APIConnectionError / APITimeoutError, which also derive from CapawesomeCloudError — so a single except CapawesomeCloudError catches every error the SDK can raise. For those, status is None.

Development

Setup

Clone the repository, then create a virtual environment and install the package with its development dependencies:

python -m venv .venv && source .venv/bin/activate
pip install -e ".[dev]"

Common commands during development:

Command Description
python -m build Build the package into dist/.
ruff check src tests examples Run the linter.
ruff format src tests examples Auto-format the code.
ruff format --check src tests examples Check formatting without writing.
mypy Type-check the package.

Testing

Tests are written with pytest and live in the tests/ directory. HTTP is mocked with RESPX, so the suite makes no network calls:

pytest                          # run the suite once
pytest --cov=capawesome_cloud   # run with a coverage report

Publishing

Releases are automated with Release Please, which derives the next version and changelog entries from Conventional Commits.

On every push to main, the Release workflow creates or updates a release pull request that bumps the version and updates CHANGELOG.md. Merging that pull request creates the git tag and GitHub release, and publishes the package to PyPI.

License

See LICENSE.

Metadata

Release files for capawesome-cloud 0.2.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for capawesome-cloud 0.2.2
File Size Uploaded Provenance
capawesome_cloud-0.2.2.tar.gz 36.1 kB With provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for capawesome-cloud 0.2.2
File Interpreter ABI Platform
capawesome_cloud-0.2.2-py3-none-any.whl Python 3 none any Details

Total release size: 80.0 kB

Release files / capawesome_cloud-0.2.2.tar.gz

Download URL capawesome_cloud-0.2.2.tar.gz
Size 36.1 kB
Tags Source
SHA-256 checksum
How to use checksums
11d6cb14f6d5997e7766d18675fd1d25c80aff66b1c45a729db8f06fe3c55d2d
BLAKE2b-256 checksum
How to use checksums
e4ea017cebbe85791617c291b07b05a2d5036201d8991baf4555ae21c3530542
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.

Transparency log

Release files / capawesome_cloud-0.2.2-py3-none-any.whl

Download URL capawesome_cloud-0.2.2-py3-none-any.whl
Size 43.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
09096abcb35086f3e482ece8a60e894f8260142237246fc1c2a182064154f0e6
BLAKE2b-256 checksum
How to use checksums
edde2e56ce39938feb5eabd52fed5aeaccadf10bdeb98c13776449d2ca36ea19
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.14

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.

Transparency log

Security for capawesome-cloud 0.2.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Full provenance

All 2 files in this release have been uploaded with provenance metadata.

Select from 2 files

Attestation for capawesome_cloud-0.2.2.tar.gz

PyPI Publish Attestation

PyPI verified that this artifact, at this checksum, originated from the publisher listed below.

Signed by GitHub Actions, verified by PyPI on Oct 4, 2026.

Transparency log

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page