This page documents
squarecloud-api 5.0, a rewrite of the SDK. Coming from v4? Read the v4 → v5 migration guide.Requirements
- Python 3.11 or newer.
- An API key (see API key and scopes).
http.client, json, ssl) and is fully typed (py.typed): responses are TypedDicts your editor and type checker understand.
Installation
- pip
- uv
- poetry
squarecloud-api and is imported as squarecloud. The installed version is squarecloud.__version__.
API key and scopes
Create a key at squarecloud.app/account/security. The SDK sends it as-is in theAuthorization header (no Bearer prefix).
A key can be limited to scopes (apps:read, apps:deploy, apps:control, ai:chat, …) and to specific apps or databases:
- A call outside those limits raises a
SquareCloudAPIErrorwith 403MISSING_SCOPEorRESOURCE_NOT_ALLOWED. - List methods (
account.me(),apps.status_all(), …) only return the resources the key can see. - An unknown, revoked or expired key is 401
ACCESS_DENIED.
SQUARECLOUD_API_KEY environment variable. Set it in the terminal where you run them:
- macOS / Linux
- Windows (PowerShell)
Creating the client
The SDK has two clients with the same groups and methods:SquareCloudis synchronous and thread-safe: share one instance between threads. Each thread reuses its own keep-alive connection.AsyncSquareCloudis the same API withawait. Each call runs the synchronous client inasyncio.to_thread, so the event loop is never blocked.
- Sync
- Async
with / async with block closes the pooled connections. Without a block, call client.close() when you are done. close() is a regular (synchronous) method on both clients.
An empty or whitespace-only key raises a ValueError in the constructor, before any request.
The async client
AsyncSquareCloud differs from SquareCloud in only three places:
- Every method returns a coroutine:
await client.apps.status(app_id). close()is synchronous: call it withoutawait.apps.realtime(app_id)is not awaited: it returns anAsyncRealtimethat you consume withasync for(see Realtime).
asyncio.gather:
Cancelling an awaiting task does not stop the request already running in its worker thread: the call still completes (or times out) in the background.
Options
AsyncSquareCloud takes the same ones.
The client keeps the key only in its private request headers: there is no
client.api_key attribute, and the SDK’s logger never writes it.Modules
The package exports
SquareCloud, AsyncSquareCloud, SquareCloudAPIError, BASE_URL, HTTPTransport, the Transport and Response protocols, Realtime, AsyncRealtime and __version__. The response types (App, RuntimeStats, Snapshot, …) live in squarecloud.types:
Conventions
Ids first, plain data back
Every method takes the resource id as its first argument and returns plain data: each response is aTypedDict, which is a regular dict at runtime (no classes, no cache), so fields the API adds later are kept. Field names are the API’s own (created_at, version_id, lastModified, joinedAt, netIO, …), so the API reference applies as-is.
- Mutations return
None, unless the API returns data (envs.*,deploys.set_webhook,deploys.link_github_app,databases.reset_credentialsand thecreatemethods). - A string result is never
None: it is''when the API sends none. - Lists come complete in one call: there is no pagination.
- Optional modifiers are keyword-only (
status(app_id, raw=True),commit(app_id, file, path="/src")). The one exception is the optionalpathoffiles.list, which can also be passed by position.
Workspace apps
Everyapp_id also accepts the composite form <appId>-<workspaceId> to act on an app shared with you through a workspace. workspaces.get() and workspaces.list() return raw ids; you build the composite id yourself:
Ids are encoded
Ids in the URL path are percent-encoded. An id that is empty,. or .. would reach a different route, so it fails locally with INVALID_ID (status 0) before anything is sent. Workspace routes send their ids in the body instead: there, INVALID_ID (400) comes from the server.
Dates
start and end arguments (see Network) take an ISO 8601 string (sent as is) or a datetime (sent in UTC). A naive datetime is treated as local time and converted to UTC, so prefer aware ones (datetime.now(UTC)). Dates in responses stay as the API sends them (ISO strings, or Unix milliseconds where the API uses them).
Timeouts
timeout bounds each socket operation: the connect and every read or write. A response that keeps sending data can take longer than timeout in total.
A
timeout of 0 or less disables every timeout, the 120 s floors included.
Calls cannot be cancelled once sent: the only stream you can stop midway is apps.realtime(), with close() from any thread. For a long upload, keep the default timeout so a dead connection is detected on connect, and run it in a thread or with AsyncSquareCloud if the rest of your program must keep going.
Account
client.account.me() returns the authenticated user plus the apps and databases the key can see.
client.account.snapshots(scope=...) lists every snapshot of the account: see Snapshots.
Platform status
client.service.status() returns the public platform status. The route needs no valid key, but the client still requires a non-empty one.
unknown means the check itself could not run: it is not evidence of an outage.
Advanced
Custom transport
transport= replaces the HTTP layer. Use it for proxies, tracing or tests. A transport is any callable with this signature:
The returned object needs
status, read(), readline() and close(): an http.client.HTTPResponse qualifies. Retries, error mapping and the {status, response} unwrapping stay in the client, so a transport only moves bytes.
HTTPTransport(timeout=30.0) is the default transport: one keep-alive connection per thread and host, gzip-compressed responses (except for streams), and timeout as the connect bound of the calls without their own timeout. You can wrap it:
client.close() closes the connections of the default transport. A custom transport that has a close() method is closed too.
Logging
The SDK logs each request atDEBUG on the squarecloud logger: method, path and status, never bodies or keys. It only attaches a NullHandler, so nothing is printed until you configure logging:
Next steps
Managing applications
Status, lifecycle, logs and metrics.
Errors
Error class, retries and rate limits.
API introduction
Base URL, authentication and a first request.
CLI quickstart
Deploy and manage apps from the terminal.

