> ## Documentation Index
> Fetch the complete documentation index at: https://docs.squarecloud.app/llms.txt
> Use this file to discover all available pages before exploring further.

# SDK Python: início rápido e cliente

> Instale o SDK Python (squarecloud-api 5), crie um cliente síncrono ou assíncrono com sua chave de API e siga as convenções: ids, datas e timeouts.

<Info>
  Esta página documenta o **`squarecloud-api` 5.0**, uma reescrita do SDK. Vindo da v4? Leia o [guia de migração v4 → v5](/pt-br/sdks/py/migrating_to_v5).
</Info>

## Requisitos

* **Python 3.11** ou superior.
* Uma chave de API (veja [Chave de API e escopos](#chave-de-api-e-escopos)).

O pacote **não tem nenhuma dependência em tempo de execução** (apenas a biblioteca padrão: `http.client`, `json`, `ssl`) e é totalmente tipado (`py.typed`): as respostas são `TypedDict`s que seu editor e seu verificador de tipos entendem.

## Instalação

<Tabs>
  <Tab title="pip">
    ```bash theme={"system"}
    pip install squarecloud-api
    ```
  </Tab>

  <Tab title="uv">
    ```bash theme={"system"}
    uv add squarecloud-api
    ```
  </Tab>

  <Tab title="poetry">
    ```bash theme={"system"}
    poetry add squarecloud-api
    ```
  </Tab>
</Tabs>

O pacote é instalado como `squarecloud-api` e importado como `squarecloud`. A versão instalada é `squarecloud.__version__`.

## Chave de API e escopos

Crie uma chave em [squarecloud.app/account/security](https://squarecloud.app/pt-br/account/security). O SDK a envia como está no header `Authorization` (sem o prefixo `Bearer`).

Uma chave pode ser limitada a **escopos** (`apps:read`, `apps:deploy`, `apps:control`, `ai:chat`, ...) e a aplicações ou bancos de dados específicos:

* Uma chamada fora desses limites lança um [`SquareCloudAPIError`](/pt-br/sdks/py/errors) com 403 `MISSING_SCOPE` ou `RESOURCE_NOT_ALLOWED`.
* Métodos de listagem (`account.me()`, `apps.status_all()`, ...) retornam apenas os recursos que a chave pode ver.
* Uma chave desconhecida, revogada ou expirada resulta em 401 `ACCESS_DENIED`.

<Warning>
  Mantenha a chave fora do seu código-fonte: leia-a do ambiente (`os.environ["SQUARECLOUD_API_KEY"]`) ou de um gerenciador de segredos.
</Warning>

Os exemplos leem a chave da variável de ambiente `SQUARECLOUD_API_KEY`. Defina-a no terminal em que você vai executá-los:

<Tabs>
  <Tab title="macOS / Linux">
    ```bash theme={"system"}
    export SQUARECLOUD_API_KEY="your-api-key"
    ```
  </Tab>

  <Tab title="Windows (PowerShell)">
    ```powershell theme={"system"}
    $env:SQUARECLOUD_API_KEY = "your-api-key"
    ```
  </Tab>
</Tabs>

## Criando o cliente

O SDK tem dois clientes com os mesmos grupos e métodos:

* **`SquareCloud`** é síncrono e **thread-safe**: compartilhe uma única instância entre threads. Cada thread reutiliza sua própria conexão keep-alive.
* **`AsyncSquareCloud`** é a mesma API com `await`. Cada chamada executa o cliente síncrono em `asyncio.to_thread`, então o event loop nunca é bloqueado.

<Tabs>
  <Tab title="Síncrono">
    ```python theme={"system"}
    import os

    from squarecloud import SquareCloud

    with SquareCloud(os.environ["SQUARECLOUD_API_KEY"]) as client:
        me = client.account.me()
        print(f"Hi {me['user']['name']}, you have {len(me['applications'])} apps")
    ```
  </Tab>

  <Tab title="Assíncrono">
    ```python theme={"system"}
    import asyncio
    import os

    from squarecloud import AsyncSquareCloud


    async def main() -> None:
        async with AsyncSquareCloud(os.environ["SQUARECLOUD_API_KEY"]) as client:
            me = await client.account.me()
            print(f"Hi {me['user']['name']}, you have {len(me['applications'])} apps")


    asyncio.run(main())
    ```
  </Tab>
</Tabs>

Os dois imprimem o nome da sua conta e o número de aplicações que a chave pode ver:

```text theme={"system"}
Hi Jane, you have 3 apps
```

Sair do bloco `with` / `async with` fecha as conexões do pool. Sem um bloco, chame `client.close()` quando terminar. `close()` é um método comum (síncrono) nos dois clientes.

Uma chave vazia ou composta apenas de espaços lança um `ValueError` no construtor, antes de qualquer requisição.

### O cliente assíncrono

`AsyncSquareCloud` difere de `SquareCloud` em apenas três pontos:

* Todo método retorna uma coroutine: `await client.apps.status(app_id)`.
* `close()` é síncrono: chame-o sem `await`.
* `apps.realtime(app_id)` **não** é aguardado: ele retorna um `AsyncRealtime` que você consome com `async for` (veja [Tempo real](/pt-br/sdks/py/realtime)).

Como cada chamada roda em uma thread de trabalho, você pode executar chamadas em paralelo com `asyncio.gather`:

```python theme={"system"}
apps, databases = await asyncio.gather(
    client.apps.status_all(),
    client.databases.status_all(),
)
```

<Note>
  Cancelar uma task em espera não interrompe a requisição que já está rodando na sua thread de trabalho: a chamada ainda termina (ou expira) em segundo plano.
</Note>

### Opções

```python theme={"system"}
import os

from squarecloud import BASE_URL, SquareCloud

client = SquareCloud(
    os.environ["SQUARECLOUD_API_KEY"],
    base_url=BASE_URL,  # "https://api.squarecloud.app/v2" (default)
    timeout=30.0,
    max_retries=2,
    user_agent="my-bot/1.0",
    transport=None,  # a custom transport (proxy, tracing, tests)
)
```

As opções são keyword-only, e o `AsyncSquareCloud` recebe as mesmas.

| Opção | Padrão | Descrição |
| - | - | - |
| `base_url` | `https://api.squarecloud.app/v2` | URL base da API. Uma `/` final é removida. Também exportada como `BASE_URL`. |
| `timeout` | `30.0` | Segundos **por operação de socket** (a conexão e cada leitura ou escrita), não para a requisição inteira. Veja [Timeouts](#timeouts). |
| `max_retries` | `2` | Novas tentativas apenas de falhas seguras (até 3 tentativas). Um valor negativo conta como `0`. Veja [Novas tentativas](/pt-br/sdks/py/errors#novas-tentativas). |
| `user_agent` | `squarecloud-sdk-py/<version>` | Substitui todo o header `User-Agent`. |
| `transport` | `HTTPTransport(timeout)` | Um transporte personalizado para proxies, tracing ou testes. Veja [Avançado](#avançado). |

<Note>
  O cliente guarda a chave apenas nos seus headers privados de requisição: não existe um atributo `client.api_key`, e o logger do SDK nunca a escreve.
</Note>

## Módulos

| Atributo | Cobre | Página |
| - | - | - |
| `client.account` | `me()`, `snapshots(scope=)` | [Conta](#conta) e [Snapshots](/pt-br/sdks/py/snapshots) |
| `client.service` | `status()` | [Status da plataforma](#status-da-plataforma) |
| `client.apps` | Obter, excluir, status, ciclo de vida, logs, métricas, domínios, load balancers | [Gerenciando aplicações](/pt-br/sdks/py/managing_application) |
| `client.apps.create` / `commit` | Uploads | [Commit e upload](/pt-br/sdks/py/commit_and_upload) |
| `client.apps.files` | Gerenciador de arquivos | [Gerenciando arquivos](/pt-br/sdks/py/managing_files) |
| `client.apps.envs` | Variáveis de ambiente | [Variáveis de ambiente](/pt-br/sdks/py/environment_variables) |
| `client.apps.deploys` | Deploys via webhook e GitHub App | [Deploys](/pt-br/sdks/py/deploys) |
| `client.apps.network` | Analytics, logs, DNS, domínio personalizado, cache | [Rede](/pt-br/sdks/py/network) |
| `client.apps.realtime` | Logs e status ao vivo | [Tempo real](/pt-br/sdks/py/realtime) |
| `client.apps.snapshots` / `client.databases.snapshots` / `client.download_snapshot` | Backups | [Snapshots](/pt-br/sdks/py/snapshots) |
| `client.databases` | Bancos de dados gerenciados | [Bancos de dados](/pt-br/sdks/py/databases) |
| `client.workspaces` | Workspaces, membros e aplicações compartilhadas | [Workspaces](/pt-br/sdks/py/workspaces) |
| `client.ai` | `chat()` | [IA](/pt-br/sdks/py/ai) |

O pacote exporta `SquareCloud`, `AsyncSquareCloud`, `SquareCloudAPIError`, `BASE_URL`, `HTTPTransport`, os protocolos `Transport` e `Response`, `Realtime`, `AsyncRealtime` e `__version__`. Os tipos de resposta (`App`, `RuntimeStats`, `Snapshot`, ...) ficam em `squarecloud.types`:

```python theme={"system"}
from squarecloud.types import App, Snapshot
```

## Convenções

### Ids primeiro, dados simples de volta

Todo método recebe o id do recurso como primeiro argumento e retorna **dados simples**: cada resposta é um `TypedDict`, que em tempo de execução é um `dict` comum (sem classes, sem cache), então os campos que a API adicionar no futuro são mantidos. Os nomes dos campos são os da própria API (`created_at`, `version_id`, `lastModified`, `joinedAt`, `netIO`, ...), então a [referência da API](/pt-br/api-reference/authentication) se aplica diretamente.

* Mutações retornam `None`, a menos que a API retorne dados (`envs.*`, `deploys.set_webhook`, `deploys.link_github_app`, `databases.reset_credentials` e os métodos `create`).
* Um resultado string nunca é `None`: ele é `''` quando a API não envia nada.
* Listas vêm completas em uma única chamada: não há paginação.
* Modificadores opcionais são **keyword-only** (`status(app_id, raw=True)`, `commit(app_id, file, path="/src")`). A única exceção é o `path` opcional de `files.list`, que também pode ser passado por posição.

Os métodos são bound methods comuns, então você pode guardar uma referência a eles:

```python theme={"system"}
restart = client.apps.restart
logs = client.apps.logs

restart(app_id)
print(logs(app_id))
```

### Aplicações de workspace

Todo `app_id` também aceita a forma composta `<appId>-<workspaceId>` para atuar sobre uma aplicação compartilhada com você por meio de um [workspace](/pt-br/sdks/py/workspaces). `workspaces.get()` e `workspaces.list()` retornam ids brutos; você mesmo monta o id composto:

```python theme={"system"}
client.apps.restart(f"{app_id}-{workspace_id}")
```

### Ids são codificados

Ids no caminho da URL são codificados com percent-encoding. Um id vazio, `.` ou `..` chegaria a uma rota diferente, então ele falha localmente com `INVALID_ID` (status `0`) antes que qualquer coisa seja enviada. As rotas de workspace enviam seus ids no corpo: nelas, o `INVALID_ID` (400) vem do servidor.

### Datas

Os argumentos `start` e `end` (veja [Rede](/pt-br/sdks/py/network)) aceitam uma string ISO 8601 (enviada como está) ou um `datetime` (enviado em UTC). Um `datetime` **naive** é tratado como horário local e convertido para UTC, então prefira os aware (`datetime.now(UTC)`). As datas nas respostas permanecem como a API as envia (strings ISO, ou milissegundos Unix onde a API os usa).

## Timeouts

`timeout` limita **cada operação de socket**: a conexão e cada leitura ou escrita. Uma resposta que continua enviando dados pode levar mais do que `timeout` no total.

| Chamada | Timeout |
| - | - |
| Todas as outras chamadas | `timeout` (30 s) por operação de socket |
| Chamadas que o servidor mantém abertas: `start`/`stop`/`restart` de aplicações, `start`/`stop` de bancos de dados, `databases.create`, `create`/`restore` de snapshots, `ai.chat` | Pelo menos **120 s** (um `timeout` maior prevalece) |
| Uploads (`apps.create`, `apps.commit`) e `files.write` acima de 1 MiB | Nenhum depois de conectado (a conexão ainda é limitada por `timeout`) |
| `download_snapshot` | `timeout` por leitura, não para o download inteiro |
| `apps.realtime` | Apenas até os headers da resposta chegarem |

Um `timeout` de `0` ou menos desativa **todos** os timeouts, incluindo os mínimos de 120 s.

As chamadas não podem ser canceladas depois de enviadas: o único stream que você pode interromper no meio é o [`apps.realtime()`](/pt-br/sdks/py/realtime), com `close()` a partir de qualquer thread. Para um upload longo, mantenha o timeout padrão para que uma conexão morta seja detectada na conexão, e execute-o em uma thread ou com o `AsyncSquareCloud` se o resto do seu programa precisar continuar rodando.

## Conta

`client.account.me()` retorna o usuário autenticado, além das aplicações e bancos de dados que a chave pode ver.

```python theme={"system"}
from datetime import datetime

me = client.account.me()
user = me["user"]

print(user["id"], user["name"], user["email"], user["plan"]["name"])
print(user["plan"]["memory"])  # {'limit', 'available', 'used'} in MB

duration = user["plan"]["duration"]
print(datetime.fromtimestamp(duration / 1000) if duration else "never expires")
```

| Campo | Descrição |
| - | - |
| `user` | `id`, `name`, `email`, `locale`, `created_at` e `plan` (`name`, `memory`, `duration`: o Unix ms em que o plano **expira**, `None` se nunca expirar) |
| `applications` | Lista de `{ id, name, desc?, ram, lang, domain?, custom?, cluster, created_at }` |
| `databases` | Lista de `{ id, name, ram, type, cluster, created_at }` |

`client.account.snapshots(scope=...)` lista todos os snapshots da conta: veja [Snapshots](/pt-br/sdks/py/snapshots#snapshots-da-conta).

## Status da plataforma

`client.service.status()` retorna o status público da plataforma. A rota não exige uma chave válida, mas o cliente ainda requer uma chave não vazia.

```python theme={"system"}
status = client.service.status()

print(status["status"])  # "online" | "degraded" | "unknown"
print(status["message"])

for name, service in status.get("services", {}).items():
    print(name, service["status"])  # "operational" | "degraded" | "outage" | "maintenance" | "unknown"
```

`unknown` significa que a própria verificação não pôde ser executada: não é evidência de uma indisponibilidade.

## Avançado

### Transporte personalizado

`transport=` substitui a camada HTTP. Use-o para proxies, tracing ou testes. Um transporte é qualquer callable com esta assinatura:

```python theme={"system"}
transport(method, url, headers, body, timeout, stream) -> Response
```

| Argumento | Descrição |
| - | - |
| `method`, `url`, `headers` | A requisição. `headers` já contém `Authorization` (nunca enviado ao host de download de snapshots), `User-Agent` e, em uploads, `Content-Length` |
| `body` | `bytes`, um iterável de chunks `bytes` (uploads, transmitidos em stream) ou `None` |
| `timeout` | O timeout por operação de socket em segundos, já aumentado para as chamadas mantidas abertas. `None` para uploads, `files.write` acima de 1 MiB e o stream em tempo real: limite a conexão deles você mesmo |
| `stream` | `True` quando quem chama lê o corpo de forma incremental (tempo real, downloads de snapshots) e pode chamar `close()` a partir de outra thread para abortá-lo |

O objeto retornado precisa de `status`, `read()`, `readline()` e `close()`: um `http.client.HTTPResponse` serve. As novas tentativas, o mapeamento de erros e o desempacotamento de `{status, response}` ficam no cliente, então um transporte apenas move bytes.

`HTTPTransport(timeout=30.0)` é o transporte padrão: uma conexão keep-alive por thread e host, respostas comprimidas com gzip (exceto em streams) e `timeout` como limite de conexão das chamadas sem timeout próprio. Você pode encapsulá-lo:

```python theme={"system"}
import os
import time

from squarecloud import HTTPTransport, SquareCloud

default = HTTPTransport()


def timed(method, url, headers, body, timeout, stream):
    started = time.perf_counter()
    response = default(method, url, headers, body, timeout, stream)
    print(method, url, response.status, f"{time.perf_counter() - started:.3f}s")
    return response


client = SquareCloud(os.environ["SQUARECLOUD_API_KEY"], transport=timed)
```

`client.close()` fecha as conexões do transporte padrão. Um transporte personalizado que tenha um método `close()` também é fechado.

### Registro de logs

O SDK registra cada requisição em `DEBUG` no logger `squarecloud`: método, caminho e status, **nunca** corpos ou chaves. Ele apenas anexa um `NullHandler`, então nada é impresso até você configurar o logging:

```python theme={"system"}
import logging

logging.basicConfig()
logging.getLogger("squarecloud").setLevel(logging.DEBUG)
```

## Próximos passos

<CardGroup cols={2}>
  <Card title="Gerenciando aplicações" icon="server" href="/pt-br/sdks/py/managing_application">
    Status, ciclo de vida, logs e métricas.
  </Card>

  <Card title="Erros" icon="triangle-exclamation" href="/pt-br/sdks/py/errors">
    Classe de erro, novas tentativas e rate limits.
  </Card>

  <Card title="Introdução à API" icon="code" href="/pt-br/api-reference/introduction">
    URL base, autenticação e uma primeira requisição.
  </Card>

  <Card title="Início rápido da CLI" icon="terminal" href="/pt-br/cli-reference/quickstart">
    Faça deploy e gerencie aplicações pelo terminal.
  </Card>
</CardGroup>


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.