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.10 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.3.0

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.3.0
File Size Uploaded Provenance
capawesome_cloud-0.3.0.tar.gz 36.6 kB With provenance Details

Built distribution (wheel)

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

Total release size: 80.4 kB

Release files / capawesome_cloud-0.3.0.tar.gz

Download URL capawesome_cloud-0.3.0.tar.gz
Size 36.6 kB
Tags Source
SHA-256 checksum
How to use checksums
69625b43b04358fb5aea809e3e5da3a033a7d69523eb840cdc750d14e7c75c33
BLAKE2b-256 checksum
How to use checksums
8d70e07cd6d5cfe356d6463fa3cd546eee973cef132dd24c94304dc606e3cdbb
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 23, 2026.

Transparency log

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

Download URL capawesome_cloud-0.3.0-py3-none-any.whl
Size 43.9 kB
Tags Python 3
SHA-256 checksum
How to use checksums
410295e579fa7a29747f20bbcedacc3fafbd585ff338cf40f9e0863ea5a202d6
BLAKE2b-256 checksum
How to use checksums
727b1cd6607861d7210cfd3edfb735a27ca5ba868a0808b35d996017249f9c6e
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via twine/7.0.0 CPython/3.13.16

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 23, 2026.

Transparency log

Security for capawesome-cloud 0.3.0

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.3.0.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 23, 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